﻿#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "LoadSimCanFunc.h"

MainWindow *g_MainWindow = NULL;
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    g_MainWindow = this;
    ui->setupUi(this);
    init();
}

MainWindow::~MainWindow()
{
    closeAll();
    exit();
    delete ui;
}

// 窗口隐藏事件
void MainWindow::hideEvent(QHideEvent *ev){
    retInfo("hide event");
    ev->accept();
}

// 窗口显示事件
void MainWindow::showEvent(QShowEvent *ev){
    retInfo("show event");
    ev->accept();
}

// 键盘按键事件
void MainWindow::keyPressEvent(QKeyEvent *event){
    // 普通键
    switch (event->key())
    {
    // DEL键
    case Qt::Key_Delete:
        break;
        // ESC键
        //        case Qt::Key_Escape:
        //            qDebug() << "Esc";
        //            break;
        // 空格键
    case Qt::Key_Space:
        break;
        // 回车键
        //        case Qt::Key_Return:
        //            qDebug() << "Enter";
        //            break;
        // F1键
        //        case Qt::Key_F1:
        //            qDebug() << "F1";
        //            break;
    }

    // 两键组合
    if(event->modifiers() == Qt::ControlModifier){
        // 如果按下了CTRL键
        //        if(event->key() == Qt::Key_Delete){
        //        }
    }

    if(event->modifiers() == Qt::AltModifier){
        // 如果按下了ALT键
        //        if(event->key() == Qt::Key_M){
        //            qDebug() << "ALT + M";
        //        }
    }

    if(event->modifiers() == Qt::ShiftModifier){
        // 如果按下了Shift键
        //        if(event->key() == Qt::Key_M){
        //            qDebug() << "Shift + M";
        //        }
    }

    // 三键组合Shift + Ctrl + A的实现
    if(event->modifiers() == (Qt::ShiftModifier | Qt::ControlModifier) && event->key() == Qt::Key_D){
        qDebug() << "CTRL + Shift + D";
    }
    if(event->modifiers() == (Qt::AltModifier | Qt::ControlModifier) && event->key() == Qt::Key_D){
        qDebug() << "CTRL + ALT + D";
    }
    if(event->modifiers() == (Qt::AltModifier | Qt::ControlModifier) && event->key() == Qt::Key_L){
        qDebug() << "CTRL + ALT + L";
    }

}

// 键盘释放事件
void MainWindow::keyReleaseEvent(QKeyEvent *event){
    // 方向UP键
    if(event->key() == Qt::Key_Up)
    {
        qDebug() << "release: "<< "up";
    }
}

void MainWindow::closeAll(void){
    if(bAutoPhoto){
        //自拍-关闭
        ui->checkBoxAutoPhoto->setChecked(false);
    }
    if(fsMvs->isGrabbing()){
        on_pushButtonStartAcquisition_clicked();
    }
    if(fsMvs->isOpen()){
        on_pushButtonDeviceDriven_clicked();
    }
    if(fsUim->isOpen()){
        on_pushButtonElectricDriven_clicked();
    }
}

//关闭事件
void MainWindow::closeEvent(QCloseEvent *event){
    closeAll();
    if(QMessageBox::question(this,
                              QString("退出"),
                              QString("系统将退出，请确认?"),
                              QMessageBox::Yes,
                              QMessageBox::No) == QMessageBox::Yes){
        event->accept();
    }
    else{
        event->ignore();
    }

}

void MainWindow::moveEvent(QMoveEvent *event){
    Q_UNUSED(event);
    // setPreviewWnd();
    // flushCutWin();
}

void MainWindow::mouseMoveEvent(QMouseEvent *event){
    Q_UNUSED(event);
    // if(fsConf->funcVar.Debug){
    //     retInfo(QString("main mouse move [%0,%1]").arg(ev->pos().x()).arg(ev->pos().y()));
    // }
}

void MainWindow::resizeEvent(QResizeEvent *event){
    Q_UNUSED(event);
    winWidth = event->size().width();
    winHeight = event->size().height();
    // set4KScreen(winWidth);

    flushSplit();
    flushOther();
    imageResize();
}

void MainWindow::imageResize(void){
    if(!this->isMaximized())return;

    winFrameWnd = (HWND)ui->labelFrameImage->winId();
    winFrameWidth = ui->labelFrameImage->width()-fsConf->mvsVar.MvsPreviewBorder*2;
    winFrameHeight = ui->labelFrameImage->height()-fsConf->mvsVar.MvsPreviewBorder*2;
    winResultWnd = (HWND)ui->labelResultImage->winId();
    winResultWidth = ui->labelResultImage->width()-fsConf->mvsVar.MvsResultBorder*2;
    winResultHeight = ui->labelResultImage->height()-fsConf->mvsVar.MvsResultBorder*2;
    retInfo(QString("resizeEvent %0 %1 preview %2 %3 result %4 %5")
                .arg(winWidth).arg(winHeight)
                .arg(winFrameWidth).arg(winFrameHeight)
                .arg(winResultWidth).arg(winResultHeight));


}

bool MainWindow::eventFilter(QObject *watched, QEvent *event){
    if(watched == ui->comboBoxImageFormat
        //        ||watched == ui->comboBoxMapMode
        ||watched == ui->comboBoxSaveFormat
        // ||watched == ui->comboBoxRotatePhoto
        ||watched == ui->spinBoxSavePara
        ||watched == ui->comboBoxSaveDpi
        ||watched == ui->doubleSpinBoxMvsExposure
        //        ||watched == ui->spinBoxBlueGainColor
        //        ||watched == ui->spinBoxGreenGainColor
        //        ||watched == ui->spinBoxRedGainColor
        // ||watched == ui->spinBoxContrast
        // ||watched == ui->spinBoxLight
        // ||watched == ui->spinBoxSaturation
        // ||watched == ui->spinBoxGamma
        // ||watched == ui->horizontalSliderExposureLines
        // ||watched == ui->horizontalSliderContrast
        // ||watched == ui->horizontalSliderLight
        // ||watched == ui->horizontalSliderSaturation
        // ||watched == ui->horizontalSliderGamma
        // ||watched == ui->spinBoxScanFrame
        // ||watched == ui->spinBoxBookFrame
        // ||watched == ui->spinBoxScanBeginTag
        // ||watched == ui->spinBoxScanSepTag
        // ||watched == ui->spinBoxBookOutTime11
        // ||watched == ui->spinBoxBookOutTime12
        // ||watched == ui->spinBoxBookOutTime21
        // ||watched == ui->spinBoxBookOutTime22
        // ||watched == ui->spinBoxAutoPhotoCanRate
        // ||watched == ui->comboBoxPhotoContourType
        )
    {
        if(event->type() == QEvent::Wheel){
            return true;
        }
    }
    return false;
    //    return MainWindow::eventFilter(watched, event);
}


void MainWindow::init(void)
{
    retInfo("init");
    retInfo(QString("main %0").arg(EXE_MAIN));

    getSysScreen();

    saveImageMutex = new QMutex();
    frameImageZoomMutex = new QMutex();
    resultImageZoomMutex = new QMutex();

    saveImageThread = nullptr;

    softKey=new SoftkeyYT88();
    keyEdit = nullptr;

    bottomTimer = nullptr;
    encodeTimer = nullptr;
    canMoveTimer = nullptr;
    procTimer = nullptr;
    isKeyCanMove = false;

    fsMvs = nullptr;
    fsUim = nullptr;
    fsConf = nullptr;

    curFrameImageZoom = 0;
    curFrameImagePosX=0;
    curFrameImagePosY=0;
    curResultImageZoom = 0;
    curResultImagePosX=0;
    curResultImagePosY=0;

    bAutoPhoto = false;
    bAutoPhotoFirst = false;

    isInitPreview = false;

    isProc = false;
    bAutoProc = false;

    initVar();
    initTime();
    initProcTime();
    initScreen();

    labelTopInfo[0] = ui->labelLineRate->text();
    labelTopInfo[1] = ui->labelFrameGrabing->text();
    labelTopInfo[2] = ui->labelImageNums->text();
    labelTopInfo[3] = ui->labelErrorNums->text();
    labelTopInfo[4] = ui->labelLostNums->text();
    labelTopInfo[5] = ui->labelLinkSpeed->text();
    labelTopInfo[6] = ui->labelFrameScreen->text();
    labelTopInfo[7] = ui->labelEncodeCounter->text();
}

void MainWindow::exit(void)
{
    retInfo("exit");
    saveVar();

    QObject::disconnect(ui->labelResultImage, SIGNAL(imageMove(int,int)), this, SLOT(recvResultImageMove(int,int)));
    QObject::disconnect(ui->labelResultImage, SIGNAL(imageZoom(int,int,int)), this, SLOT(recvResultImageZoom(int,int,int)));
    // QObject::disconnect(ui->labelFrameImage, SIGNAL(imageMove(int,int)), this, SLOT(recvFrameImageMove(int,int)));
    // QObject::disconnect(ui->labelFrameImage, SIGNAL(imageZoom(int,int,int)), this, SLOT(recvFrameImageZoom(int,int,int)));

    relePreview();

    if(procTimer !=nullptr){
        procTimer->stop();
        delete procTimer;
    }
    if(canMoveTimer !=nullptr){
        canMoveTimer->stop();
        delete canMoveTimer;
    }
    if(encodeTimer !=nullptr){
        encodeTimer->stop();
        delete encodeTimer;
    }
    if(bottomTimer !=nullptr){
        bottomTimer->stop();
        delete bottomTimer;
    }

    if(fsMvs != nullptr)
        fsMvs->closeCamera();
    delete fsMvs;
    if(fsUim != nullptr)
        delete fsUim;
    delete fsConf;
    if(keyEdit !=nullptr){
        delete keyEdit;
    }
    delete softKey;
    delete resultImageZoomMutex;
    delete frameImageZoomMutex;
    delete saveImageMutex;
}

int MainWindow::getSoftKey(void){
    int ret = 0;

    if(softKey->IsLoad){
        ret++;
    }
    if(softKey->IsOpen){
        ret++;
    }
    return ret;
}

int MainWindow::getSoftKeyVer(void){
    if(getSoftKey()<2){
        return 0;
    }
    int ver = 0;
    if(softKey->NT_GetIDVersion(&ver) != 0)
    {
        ver = 0;
    }
    int exVer = 0;
    if(softKey->NT_GetVersionEx(&exVer) != 0)
    {
        exVer = 0;
    }
    return (exVer*100+ver);
}

QString MainWindow::getSoftKeyChipId(void){
    if(getSoftKey()<2){
        return QString("");
    }
    char chipId[128]="";
    softKey->GetChipID(chipId);
    return QString("%0").arg(chipId);
}

QString MainWindow::getSoftKeyId(void){
    if(getSoftKey()<2){
        return QString("");
    }
    DWORD ID1,ID2;
    if(softKey->GetID(&ID1,&ID2)!=0)
    {
        ID1 = 0;
        ID2 = 0;
    }
    return QString("%0%1")
        .arg(QString::number(ID1,16).toUpper().rightJustified(2,QChar('0')))
        .arg(QString::number(ID2,16).toUpper().rightJustified(2,QChar('0')));
}

QString MainWindow::getSoftKeyPass(void){
    return QString("%0%1").arg(getSoftKeyChipId()).arg(getSoftKeyId());
}

//初始化变量
void MainWindow::initVar(void)
{
    //配置
    initConfVar();
    //电机
    initUimVar();
    //摄像头
    initMvsVar();
}

//保存变量
void MainWindow::saveVar(void)
{
    retInfo(QString("save var"));
    if(curResultDirList.count()&&curResultDirIndex>=0){
        QDir dir(curResultDirList[curResultDirIndex]);
        qStrToCstr(dir.dirName(),fsConf->listVar.ListCurDir,sizeof(fsConf->listVar.ListCurDir));
    }
    if(curResultFileList.count()&&curResultFileIndex>=0){
        QFileInfo file(curResultFileList[curResultFileIndex]);
        qStrToCstr(file.fileName(),fsConf->listVar.ListCurName,sizeof(fsConf->listVar.ListCurName));
    }
    fsConf->saveConfigListSave();
}

void MainWindow::initConfVar(void)
{
    if(fsConf != nullptr){
        delete fsConf;
        fsConf = nullptr;
    }
    fsConf = new fsConfig();
    fsConf->setUiName(QString("%0/%1/ui.ini").arg(getCurPath()).arg(CONF_PATH));
    fsConf->readUi();
    fsConf->setConfName(QString("%0/%1").arg(getCurPath()).arg(CONF_PATH),fsConf->winVar.ConfName);
    fsConf->readConf();
    setLog(fsConf->funcVar.Log);
    retInfo(QString("log %0").arg(fsConf->funcVar.Log));
}

void MainWindow::initUimVar(void)
{
    if(fsUim != nullptr){
        delete fsUim;
        fsUim = nullptr;
    }
    fsUim = new UIM(QString("%0/Uim/UISimCanFunc.dll").arg(getCurPath()));
    fsUim->conf = fsConf;
    fsUim->Init();
    retInfo(QString("uimDll init %0").arg(fsUim->ret));
}

// 初始定时器
void MainWindow::initTime(void)
{
    bottomTimer = new QTimer(this);
    connect(bottomTimer, SIGNAL(timeout()), this, SLOT(showBottomTimer()));
    bottomTimer->start(500);
}

void MainWindow::initEncodeTimer(void){
    if(encodeTimer == nullptr){
        encodeTimer = new QTimer(this);
        connect(encodeTimer, SIGNAL(timeout()), this, SLOT(updateCanEncodeTimer()));
        retInfo("init encode timer");
    }
}

void MainWindow::initCanMoveTimer(void){
    if(canMoveTimer == nullptr){
        canMoveTimer = new QTimer(this);
        connect(canMoveTimer, SIGNAL(timeout()), this, SLOT(updateCanMoveTimer()));
        retInfo("init focus auto timer");
    }
}

void MainWindow::initProcTime(void)
{
    procTimer = new QTimer(this);
    connect(procTimer, SIGNAL(timeout()), this, SLOT(updateProcTimer()));
}

//初始化屏幕
void MainWindow::initScreen(void)
{
    setSplitterListSize(fsConf->designVar.SplitterPhotoSizes,splitterPhotoSizes);
    setSplitterListSize(fsConf->designVar.SplitterMainSizes,splitterMainSizes);
    setSplitterListSize(fsConf->designVar.SplitterWindowSizes,splitterWindowSizes);

    ui->comboBoxSaveFormat->blockSignals(true);
    ui->comboBoxSaveFormat->clear();
    ui->comboBoxSaveFormat->addItems(QString(fsConf->designVar.SaveFileExt).split(","));
    ui->comboBoxSaveFormat->setCurrentIndex(fsConf->designVar.SaveFormat);
    ui->comboBoxSaveFormat->blockSignals(false);

    ui->spinBoxSavePara->setValue(fsConf->designVar.Para);

    ui->checkBoxSaveHeight->setChecked(fsConf->designVar.SaveHeight);

    ui->comboBoxSaveDpi->blockSignals(true);
    ui->comboBoxSaveDpi->clear();
    ui->comboBoxSaveDpi->addItems(QString(fsConf->designVar.SaveDPIList).split(","));
    ui->comboBoxSaveDpi->blockSignals(false);

    ui->lineEditResultSavePath->setText(QString("%0").arg(fsConf->listVar.SaveResultPath));
    ui->lineEditImageSavePath->setText(QString("%0").arg(fsConf->listVar.SaveImagePath));
    ui->comboBoxSaveDpi->setCurrentText(QString("%0").arg(fsConf->designVar.SaveDPI));

    ui->spinBoxRightRate->setValue(fsConf->uimVar.UIMCanRateRight);
    ui->spinBoxAutoPhotoCanRate->setValue(fsConf->uimVar.UIMCanRatePhoto);
    ui->checkBoxEncodeStop->setChecked(fsConf->uimVar.UIMCanEncodeStop);

    ui->checkBoxNonContourTwoBorder->setChecked(fsConf->procVar.ContourTwoBorder);
    ui->spinBoxContourThreshold->setValue(fsConf->procVar.ContourThresh);
    ui->spinBoxContourGaussian->setValue(fsConf->procVar.ContourGaussian);
    ui->spinBoxContourMinWidth->setValue(fsConf->procVar.ContourMinWidth);
    ui->spinBoxContourMinHeight->setValue(fsConf->procVar.ContourMinHeight);
    ui->spinBoxUpDownBorder->setValue(fsConf->procVar.ContourUpDownBorder);
    ui->spinBoxLeftRightBorder->setValue(fsConf->procVar.ContourLeftRightBorder);
    ui->spinBoxImageMaxWidth->setValue(fsConf->procVar.ProcImageWidth);

    flushLogo();
    flushSplit();
    flushOther();

    initMvsScreen();
    initUimScreen();

    QObject::connect(ui->labelResultImage, SIGNAL(imageMove(int,int)), this, SLOT(recvResultImageMove(int,int)));
    QObject::connect(ui->labelResultImage, SIGNAL(imageZoom(int,int,int)), this, SLOT(recvResultImageZoom(int,int,int)));
    // QObject::connect(ui->labelFrameImage, SIGNAL(imageMove(int,int)), this, SLOT(recvFrameImageMove(int,int)));
    // QObject::connect(ui->labelFrameImage, SIGNAL(imageZoom(int,int,int)), this, SLOT(recvFrameImageZoom(int,int,int)));

    ui->pushButtonDirRen->setVisible(false);
    on_pushButtonDirFlush_clicked();
    flushProc();
}

//电机初始化
void MainWindow::initUimScreen(void){
    retInfo("init uim screen");

    ui->pushButtonFocusUp->setEnabled(fsUim->getFocusId()>0);
    ui->pushButtonFocusSet->setEnabled(fsUim->getFocusId()>0&&fsUim->isCanSet(fsUim->getFocusId()));
    ui->pushButtonFocusDown->setEnabled(fsUim->getFocusId()>0);
    ui->pushButtonFocusReset->setEnabled(fsUim->getFocusId()>0);
    if(!fsConf->uimVar.Debug){
        ui->pushButtonFocusReset->hide();
    }

    ui->pushButtonRightMove->setEnabled(fsUim->getRightId()>0&&!bAutoPhoto);
    ui->spinBoxRightRate->setEnabled(fsUim->getRightId()>0&&!bAutoPhoto);

    ui->checkBoxAutoPhoto->setEnabled(fsUim->getRightId()>0&&fsMvs->isOpen());
}

//摄像头初始化
void MainWindow::initMvsScreen(void)
{
    retInfo("init mvs screen");

    ui->pushButtonDeviceDriven->setEnabled(fsMvs->isDev()&&!fsMvs->isGrabbing());
    ui->pushButtonStartAcquisition->setEnabled(fsMvs->isOpen());

    ui->comboBoxImageFormat->setEnabled(fsMvs->isOpen()&&!fsMvs->isGrabbing());
    ui->spinBoxMvsWidth->setEnabled(fsMvs->isOpen()&&!fsMvs->isGrabbing());
    ui->spinBoxMvsHeight->setEnabled(fsMvs->isOpen()&&!fsMvs->isGrabbing());
    ui->spinBoxMvsLineRate->setEnabled(fsMvs->isOpen());
    ui->checkBoxMvsLineRate->setEnabled(fsMvs->isOpen());
    ui->doubleSpinBoxMvsExposure->setEnabled(fsMvs->isOpen());
    ui->checkBoxTriggerMode->setEnabled(fsMvs->isOpen());
    ui->spinBoxPreDivider->setEnabled(fsMvs->isOpen());
    ui->spinBoxMultiplier->setEnabled(fsMvs->isOpen());
    ui->spinBoxPostDivider->setEnabled(fsMvs->isOpen());
    ui->checkBoxPRNUCEnable->setEnabled(fsMvs->isOpen());

    ui->pushButtonPhotograph->setEnabled(fsMvs->isOpen()&&fsMvs->isGrabbing());
    ui->checkBoxAutoPhoto->setEnabled(fsUim->getRightId()>0&&fsMvs->isOpen());
}

//海康机器人
void MainWindow::initMvsVar(bool isShow)
{
    if(fsMvs == nullptr){
        fsMvs = new MVS(fsConf);
    }
    fsMvs->Init();
    retInfo(QString("mvs init %0").arg(isMvs()));
    if(isMvs()){
        ui->lineEditMvsInfo->setText(fsMvs->getMvsInfo());
        ui->comboBoxDevice->blockSignals(true);
        ui->comboBoxDevice->addItem(fsMvs->getDeviceName());
        ui->comboBoxDevice->blockSignals(false);
        on_comboBoxDevice_currentIndexChanged(0);
    }else{
        ui->lineEditMvsInfo->setText("未检测有效设备");
        ui->comboBoxDevice->clear();
        if(isShow){
            QMessageBox::warning(this,
                                 "提示",
                                 "未检测到照相设备，请检查连线");
        }
    }
}

//海康摄像头
bool MainWindow::isMvs(void){
    if(fsMvs != nullptr){
        return fsMvs->isDev();
    }
    return false;
}

//实际行频
void MainWindow::showTopLineRate(void){
    ui->labelLineRate->setText(QString("%0:%1Hz").arg(labelTopInfo[0]).arg(getNumber(fsMvs->getPara().ResultingLineRate)));
}

//采集帧率
void MainWindow::showTopFrameGrabing(void){
    ui->labelFrameGrabing->setText(QString("%0:%1(fps)").arg(labelTopInfo[1]).arg(getNumber(fsMvs->getPara().ResultingFrameRate)));
}

//图像数
void MainWindow::showTopImageNums(void){
    ui->labelImageNums->setText(QString("%0:%1").arg(labelTopInfo[2]).arg(fsMvs->getPara().ImageNums));
}

//错误数
void MainWindow::showTopErrorNums(void){
    ui->labelErrorNums->setText(QString("%0:%1").arg(labelTopInfo[3]).arg(fsMvs->getPara().ErrorNums));
}

//丢包数
void MainWindow::showTopLostNums(void){
    ui->labelLostNums->setText(QString("%0:%1").arg(labelTopInfo[4]).arg(fsMvs->getPara().LostNums));
}

//带宽
void MainWindow::showTopLinkRate(void){
    ui->labelLinkSpeed->setText(QString("%0:%1(Mbps)").arg(labelTopInfo[5]).arg(getNumber(fsMvs->getPara().DeviceLinkSpeed)));
}

//显示帧率
void MainWindow::showTopFrameScreen(void){
    ui->labelFrameScreen->setText(QString("%0:%1帧").arg(labelTopInfo[6]).arg(fsMvs->getPara().AcquisitionBurstFrameCount));
}

//编码计数
void MainWindow::showTopEncodeCounter(void){
    ui->labelEncodeCounter->setText(QString("%0:%1").arg(labelTopInfo[7]).arg(fsMvs->getPara().EncoderCounter));
}

// 底栏-刷新图像
void MainWindow::showBottomInfo(const QString msg)
{
    ui->labelImageInfo->setText(msg);
    ui->labelImageInfo->update();
}

// 底栏-刷新
void MainWindow::showBottomAlarm(const QString msg){
    ui->labelAlarm->setText(msg);
    ui->labelAlarm->update();
}
void MainWindow::showBottomMvsStatus(const QString msg){
    ui->labelMvsStatus->setText(msg);
    ui->labelMvsStatus->update();
}
void MainWindow::showBottomCanStatus(const QString msg){
    ui->labelCanStatus->setText(msg);
    ui->labelCanStatus->update();
}
void MainWindow::showBottomResult(const QString msg){
    ui->labelResult->setText(msg);
    ui->labelResult->update();
}

void MainWindow::flushAutoPhotoInfo(void){
    fsMvs->getEncode();
    fsUim->getPos();
    ui->lineEditAutoPhotoInfo->setText(QString("%0 %1,%2 %3")
                                           .arg(fsMvs->curFrameEncodeCounter)
                                           .arg(fsMvs->curFrameEncodeTimer)
                                           .arg(fsUim->curFramePosCounter)
                                           .arg(fsUim->curFramePosTimer));
}

// 底栏-刷新时间
void MainWindow::showBottomTimer(void)
{
    if(isMvs()){
        if(fsMvs->isOpen()){
            fsMvs->getUptime();
            ui->labelUptime->setText(QString("%0:%1:%2")
                                         .arg(fsMvs->getPara().DeviceUptime/3600)
                                         .arg((fsMvs->getPara().DeviceUptime%3600)/60)
                                         .arg(fsMvs->getPara().DeviceUptime%60));
        }else{
            ui->labelUptime->setText("");
        }
        if(fsConf->designVar.FrameEnable&&fsMvs->isGrabbing()){
            fsMvs->getResulting();
            showTopLineRate();
            showTopFrameGrabing();
            showTopLinkRate();
            showTopFrameScreen();
            showTopEncodeCounter();
            //判断编码自停
            if(bAutoPhoto && fsConf->uimVar.UIMCanEncodeStop){
                if(fsMvs->isEncodeOver(fsConf->uimVar.UIMCanEncodeOver)){
                    flushAutoPhotoInfo();
                    if(fsMvs->curFrameEncodeCounter == 0){
                        ui->checkBoxAutoPhoto->setChecked(false);
                    }
                }
            }
        }else{
            ui->labelLineRate->setText(labelTopInfo[0]);
            ui->labelFrameGrabing->setText(labelTopInfo[1]);
            ui->labelImageNums->setText(labelTopInfo[2]);
            ui->labelErrorNums->setText(labelTopInfo[3]);
            ui->labelLostNums->setText(labelTopInfo[4]);
            ui->labelLinkSpeed->setText(labelTopInfo[5]);
            ui->labelFrameScreen->setText(labelTopInfo[6]);
            ui->labelEncodeCounter->setText(labelTopInfo[7]);
        }
    }else{
        if(fsConf->mvsVar.AutoFind){
            //自动搜索MVS设备
            initMvsVar(false);
            initMvsScreen();
        }
    }
    if(!this->isMaximized()){
        if(fsConf->winVar.WindowMax){
            setWindowState(Qt::WindowMaximized);
        }
    }
    QDateTime time = QDateTime::currentDateTime();
    ui->labelTime->setText(time.toString(" yyyy-MM-dd hh:mm:ss dddd"));
}

void MainWindow::updateCanEncodeTimer(void){
    // if(!bEncodeCount)return;
    // retInfo(QString("can move left-%0 right-%1").arg(fsUim->getCanLeftMove()).arg(fsUim->getCanRightMove()));
    // if(isEncodeStop()){
    //     encodeTimer->stop();
    //     ui->checkBoxEncodeCount->setChecked(false);
    //     on_pushButtonAutoPhotoStop_clicked();
    // }else{
    //     ui->lineEditCanEncodeInfo->setText(QString("encode %0").arg(curAutoPhotoLastQec));
    // }
}

//电机移动定时器：动态显示当前位置，判断是否超时或
void MainWindow::updateCanMoveTimer(void){
    qint64 ms = QDateTime::currentMSecsSinceEpoch()-curCanMoveTimer;

    // retInfo(QString("updateCanMoveTimer %0 %1").arg(fsUim->getCanFocusMoveDirection()).arg(ms));
    bool moveStop = false;
    if(ms>fsConf->uimVar.UIMCanLimitTimer){
        //连续移动超时
        moveStop = true;
    }
    bool isMove = false;
    if(fsUim->getCanFocusMoveDirection()!=0){
        //显示位置
        isMove = true;
        if(moveStop&&isKeyCanMove || getCanFocusLimitPos()){
            isKeyCanMove = false;
            if(fsUim->isFocusId()){
                //停止
                fsUim->canSetSPD(fsUim->getFocusId(),0);
                // fsUim->canSetSTP(fsUim->getFocusId(),0);
                fsUim->setCanFocusMoveDirection(0);
            }
        }
    }
    //定时停止
    if(!isMove){
        canMoveTimer->stop();
    }
    flushCanState();
}

bool MainWindow::getCanFocusLimitPos(const int direction){
    int nDirection = direction;
    int pos = fsUim->getFocusPos();
    if(!nDirection){
        nDirection = fsUim->getCanFocusMoveDirection();
    }
    // retInfo(QString("getCanFocusLimitPos %0 %1 pos %2 %3 limit %4 %5").arg(nDirection).arg(pos)
    //             .arg(fsConf->uimVar.UIMCanFocusOrg).arg(fsConf->uimVar.UIMCanFocusFar)
    //             .arg(fsConf->uimVar.UIMCanFocusLimit1).arg(fsConf->uimVar.UIMCanFocusLimit2));
    if(nDirection > 0){
        if(fsConf->uimVar.UIMCanFocusOrg
            &&(fsConf->uimVar.UIMCanFocusFar>0)
            &&(fsConf->uimVar.UIMCanFocusLimit2>0)
            &&(pos>(fsConf->uimVar.UIMCanFocusFar-fsConf->uimVar.UIMCanFocusLimit2))){
            retInfo(QString("Focus %0 limit far").arg(pos));
            return true;
        }
    }
    if(nDirection < 0){
        if(fsConf->uimVar.UIMCanFocusOrg
            &&(fsConf->uimVar.UIMCanFocusLimit1>0)
            &&(pos<fsConf->uimVar.UIMCanFocusLimit1)){
            retInfo(QString("Focus %0 limit org").arg(pos));
            return true;
        }
    }
    return false;
}

// 刷新LOGO
void MainWindow::flushLogo(void)
{
    retInfo("flush logo");
    setWindowTitle(QString("%0 Ver[%1]")
                       .arg(fsConf->winVar.Title)
                       .arg(EXE_VERSION)
                   /*.arg(getSoftKey())
                   .arg(getSoftKeyVer())
                   .arg(getSoftKeyChipId())
                   .arg(getSoftKeyId())*/);
    setWindowIcon(QIcon(":/img/logo.ico"));
    // int w,h;
    // if(is4KScreen()){
    //     w = fsConf->designVar.LogoTitleWidth4K;
    //     h = fsConf->designVar.LogoTitleHeight4K;
    // }else{
    //     w = fsConf->designVar.LogoTitleWidth;
    //     h = fsConf->designVar.LogoTitleHeight;
    // }
    // if(w == 0 || h == 0)
    // {
    //     w = 200;
    //     h = 72;
    // }
}

// 刷新窗口分割设置
void MainWindow::flushSplit(void)
{
    if(!this->isMaximized())return;
    retInfo("flushSplit");

    if(ui->splitterPhoto->count()==splitterPhotoSizes.count()){
        ui->splitterPhoto->setSizes(splitterPhotoSizes);
    }
    if(ui->splitterMain->count()==splitterMainSizes.count()){
        ui->splitterMain->setSizes(splitterMainSizes);
    }
    if(ui->splitterWindow->count()==splitterWindowSizes.count()){
        ui->splitterWindow->setSizes(splitterWindowSizes);
    }
}

void MainWindow::flushPhotoButton(void){
    QPixmap pixmap;
    QPixmap fpixmap;
    int w,h;
    if(is4KScreen()){
        w = fsConf->designVar.LogoPhotoWidth4K;
        h = fsConf->designVar.LogoPhotoHeight4K;
    }else{
        w = fsConf->designVar.LogoPhotoWidth;
        h = fsConf->designVar.LogoPhotoHeight;
    }
    QString sheet;
    sheet = fsConf->designVar.LogoPhotoSheet1;
    ui->pushButtonPhotograph->resize(w, h);
    ui->pushButtonPhotograph->setStyleSheet(sheet);
    ui->pushButtonPhotograph->setText("");
    pixmap = QPixmap::fromImage(QImage(":/img/photo.jpg"));
    fpixmap = pixmap.scaled(w, h, Qt::IgnoreAspectRatio);
    ui->pushButtonPhotograph->setIcon(QIcon(fpixmap));
    ui->pushButtonPhotograph->setIconSize(QSize(w, h));
    retInfo(QString("flushPhotoButton %0 %1").arg(w).arg(h));

}

// 控件图片设置
void MainWindow::flushOther(void){
    retInfo("flush other");
    QString sheet;

    // 拍照按钮
    flushPhotoButton();
    // 设置comboBox Height
    if(is4KScreen()){
        sheet = getComboBoxSheet(fsConf->designVar.ComboBoxItemHeight4K);
    }else{
        sheet = getComboBoxSheet(fsConf->designVar.ComboBoxItemHeight);
    }
    ui->comboBoxDevice->setStyleSheet(sheet);
    ui->comboBoxDevice->setView(new QListView());
    ui->comboBoxSaveFormat->setStyleSheet(sheet);
    ui->comboBoxSaveFormat->setView(new QListView());
    ui->comboBoxSaveDpi->setStyleSheet(sheet);
    ui->comboBoxSaveDpi->setView(new QListView());
    ui->comboBoxImageFormat->setStyleSheet(sheet);
    ui->comboBoxImageFormat->setView(new QListView());
    ui->comboBoxResultDir->setStyleSheet(sheet);
    ui->comboBoxResultDir->setView(new QListView());

    ui->pushButtonFocusReset->setText("");
    ui->pushButtonFocusReset->setIcon(QIcon(QPixmap::fromImage(QImage(":/img/flush.png"))));

    ui->pushButtonDirFlush->setText("");
    ui->pushButtonDirFlush->setIcon(QIcon(QPixmap::fromImage(QImage(":/img/flush.png"))));

    //电机名称
    ui->labelFocus->setText(fsConf->uimVar.UIMFocusLabel);
    ui->pushButtonFocusUp->setText(fsConf->uimVar.UIMFocusMoveTitle[0]);
    ui->pushButtonFocusDown->setText(fsConf->uimVar.UIMFocusMoveTitle[1]);

}

void MainWindow::flushProc(void){
    ui->checkBoxContourRecognition->setEnabled(curResultFileList.count()&&!bAutoProc);
    ui->checkBoxNonContourTwoBorder->setEnabled(curResultFileList.count()&&!bAutoProc);
    ui->spinBoxContourThreshold->setEnabled(curResultFileList.count()&&!bAutoProc);
    ui->spinBoxContourGaussian->setEnabled(curResultFileList.count()&&!bAutoProc);
    ui->spinBoxContourMinWidth->setEnabled(curResultFileList.count()&&!bAutoProc);
    ui->spinBoxContourMinHeight->setEnabled(curResultFileList.count()&&!bAutoProc);
    ui->spinBoxUpDownBorder->setEnabled(curResultFileList.count()&&!bAutoProc);
    ui->spinBoxLeftRightBorder->setEnabled(curResultFileList.count()&&!bAutoProc);
    ui->spinBoxImageMaxWidth->setEnabled(curResultFileList.count()&&!bAutoProc);

    ui->pushButtonContourCut->setEnabled(curResultFileList.count()&&isProc&&!bAutoProc);
    ui->pushButtonContourAdd->setEnabled(curResultFileList.count()&&isProc&&!bAutoProc);
    ui->pushButtonAutoContour->setEnabled(curResultFileList.count()&&isProc);
}

void MainWindow::flushMvsState(void){
    if(fsMvs->isOpen()){
        retInfo("flushMvsState");
        //分辨率
        ui->spinBoxMvsWidth->setMaximum(fsMvs->getPara().WidthMax);
        ui->spinBoxMvsWidth->setValue(fsMvs->getPara().Width);
        ui->spinBoxMvsHeight->setMaximum(fsMvs->getPara().HeightMax);
        ui->spinBoxMvsHeight->setValue(fsMvs->getPara().Height);
        //图像格式
        ui->comboBoxImageFormat->setCurrentIndex(fsMvs->getPara().ImageFormat);
        //行频设置
        ui->spinBoxMvsLineRate->setValue(fsMvs->getPara().AcquisitionLineRate);
        ui->checkBoxMvsLineRate->setChecked(fsMvs->getPara().AcquisitionLineRateEnable);
        //触发
        ui->comboBoxTriggerSelector->setCurrentIndex(fsMvs->getPara().TriggerSelector);
        ui->checkBoxTriggerMode->setChecked(fsMvs->getPara().TriggerMode);
        ui->comboBoxTriggerSource->setCurrentIndex(fsMvs->getPara().TriggerSource);
        //曝光时间
        ui->doubleSpinBoxMvsExposure->setMinimum(fsMvs->getPara().ExposureTimeMin);
        ui->doubleSpinBoxMvsExposure->setMaximum(fsMvs->getPara().ExposureTimeMax);
        ui->doubleSpinBoxMvsExposure->setValue(fsMvs->getPara().ExposureTime);
        //分频
        ui->comboBoxInputSource->setCurrentIndex(fsMvs->getPara().InputSource);
        ui->spinBoxPreDivider->setValue(fsMvs->getPara().PreDivider);
        ui->spinBoxMultiplier->setValue(fsMvs->getPara().Multiplier);
        ui->spinBoxPostDivider->setValue(fsMvs->getPara().PostDivider);
        //校正
        ui->checkBoxPRNUCEnable->setChecked(fsMvs->getPara().PRNUCROIEnable);
    }
}

void MainWindow::flushCanState(void){
    if(fsUim->isFocusId()){
        //显示当前位置
        int pos = fsUim->getFocusPos();
        // retInfo(QString("flushCanState %0").arg(pos));
        ui->lineEditFocusCanPos->setText(QString("%0").arg(pos));
        ui->pushButtonFocusSet->setEnabled(fsUim->getFocusId()>0&&fsUim->isCanSet(fsUim->getFocusId()));
    }
}

void MainWindow::on_splitterPhoto_splitterMoved(int pos, int index)
{
    retInfo(QString("on_splitterPhoto_splitterMoved %0 %1 ").arg(pos).arg(index));

    QList<int> sizes = ui->splitterPhoto->sizes();
    QString info="";
    setSplitterSizeStr(sizes, info);
    qStrToCstr(info,fsConf->designVar.SplitterPhotoSizes,sizeof(fsConf->designVar.SplitterPhotoSizes));

    retInfo(QString("splitterPhoto [%0]").arg(info));
    fsConf->saveConfigDesignWindow();

    imageResize();
}


void MainWindow::on_splitterWindow_splitterMoved(int pos, int index)
{
    retInfo(QString("on_splitterWindow_splitterMoved %0 %1 ").arg(pos).arg(index));
    QList<int> sizes = ui->splitterWindow->sizes();
    QString info="";
    setSplitterSizeStr(sizes, info);
    qStrToCstr(info,fsConf->designVar.SplitterWindowSizes,sizeof(fsConf->designVar.SplitterWindowSizes));

    retInfo(QString("splitterWindow [%0]").arg(info));
    fsConf->saveConfigDesignWindow();

    imageResize();
}


void MainWindow::on_splitterMain_splitterMoved(int pos, int index)
{
    retInfo(QString("on_splitterMain_splitterMoved %0 %1 ").arg(pos).arg(index));
    QList<int> sizes = ui->splitterMain->sizes();
    QString info="";
    setSplitterSizeStr(sizes, info);
    qStrToCstr(info,fsConf->designVar.SplitterMainSizes,sizeof(fsConf->designVar.SplitterMainSizes));

    retInfo(QString("splitterMain [%0]").arg(info));
    fsConf->saveConfigDesignWindow();

    imageResize();
}

void MainWindow::flushPushButton(QPushButton *button, bool checked){
    if(checked){
        button->setStyleSheet("color:red");
    }else{
        button->setStyleSheet("color:black");
    }
}

//相机控制
void MainWindow::on_pushButtonDeviceDriven_clicked()
{
    //MVS
    if(fsMvs->isOpen()){
        //关闭
        showBottomAlarm("MVS关闭");
        fsMvs->closeCamera();
    }else{
        //启动
        showBottomAlarm("MVS启动");
        fsMvs->openCamera();
    }
    flushPushButton(ui->pushButtonDeviceDriven,fsMvs->isOpen());
    flushMvsState();
    initMvsScreen();
    if(fsMvs->isOpen()){
        //关闭
        // fsMvs->AddEvent();
        ui->pushButtonDeviceDriven->setText(QString("%0").arg(fsConf->mvsVar.MvsCloseTitle));
    }else{
        //启动
        ui->pushButtonDeviceDriven->setText(QString("%0").arg(fsConf->mvsVar.MvsStartTitle));
    }
}

//电动控制
void MainWindow::on_pushButtonElectricDriven_clicked()
{
    //电机
    if(fsUim->isOpen()){
        if(fsUim->isRightMove()){
            on_pushButtonRightMove_clicked();
        }
        //关闭
        fsUim->canRightOff(true);
        fsUim->canFocusOff(true);
        fsUim->canCloseGateWay();
        QObject::disconnect(this, SIGNAL(SendRTCNMsg(QString,int,int)), this, SLOT(retCanMsg(QString,int,int)));
        showBottomCanStatus(fsConf->uimVar.UIMCloseTitle);
    }else{
        //启动
        if(fsUim->canOpenGateWay()){
            initEncodeTimer();
            initCanMoveTimer();
            canCallback();
            showBottomCanStatus(fsConf->uimVar.UIMStartTitle);
        }else{
            showBottomCanStatus("启动失败");
        }
    }
    flushCanState();
    initUimScreen();
    //
    flushPushButton(ui->pushButtonElectricDriven,fsUim->isOpen());
    if(fsUim->isOpen()){
        //关闭
        ui->pushButtonElectricDriven->setText(QString("%0").arg(fsConf->uimVar.UIMCloseTitle));
    }else{
        //启动
        ui->pushButtonElectricDriven->setText(QString("%0").arg(fsConf->uimVar.UIMStartTitle));
    }
}

// 回调信息
void MainWindow::canCallback(void){
    retInfo(QString("can[%0] Callback").arg(fsUim->getIndex()));
    QObject::connect(this, SIGNAL(SendRTCNMsg(QString,int,int)), this, SLOT(retCanMsg(QString,int,int)));
    UIMRegRtcnCallBack(0,fsUim->getIndex(),MainWindow::StaticRcvRtcnNotify);
}
//处理电机返回信息
void MainWindow::retCanMsg(QString msg,int code,int node){
    // Q_UNUSED(code);
    // emit msg
    //code:113/241-S1传感1通知,114/242-S2传感2通知,115/243-S3传感3通知,117/245-STP到达通知,118-ORG零点通知
    if(fsUim->isRightId(node)){
        return;
    }
    // retInfo(msg);
    if(fsUim->isFocusId(node)){
        //上下
        if(code==117&&!isKeyCanMove&&canMoveTimer->isActive()){
            canMoveTimer->stop();
        }
        flushCanState();
        return;
    }
}
void MainWindow::StaticRcvRtcnNotify(unsigned int dwDevIndex, P_CAN_MSG_OBJ pRtcnMsgObj, unsigned int dwMsgLen)
{
    g_MainWindow->RcvRtcnNotify(dwDevIndex,pRtcnMsgObj,dwMsgLen);
}
void MainWindow::RcvRtcnNotify(unsigned int dwDevIndex, P_CAN_MSG_OBJ pRtcnMsgObj, unsigned int dwMsgLen)
{
    Q_UNUSED(dwMsgLen);
    unsigned int dwCanNodeId = ((pRtcnMsgObj->ID>>3)&0x060)+((pRtcnMsgObj->ID>>19)&0x01F);
    unsigned int iRCW = pRtcnMsgObj->ID&0x0FF;
    //    unsigned int iData = pRtcnMsgObj->Data[0]&0x0FF;
    QString strRTCNType = QString();
    bool isSend = true;
    switch (iRCW)
    {
    case 62:
    {
        strRTCNType = QString::fromLocal8Bit("%0 %1 %2 %3 %4").arg("UID900").arg(pRtcnMsgObj->Data[0]).arg(pRtcnMsgObj->Data[1]).arg(pRtcnMsgObj->Data[2]).arg(pRtcnMsgObj->Data[3]);
    }
    break;
    case 113:
    {
        if(fsUim->isFocusId(dwCanNodeId)){
            // if(fsUim->canFocusResetMark == 2){
            //     fsUim->canFocusResetMark++;
            //     retInfo(QString("对焦复位-%0").arg(fsUim->canFocusResetMark));
            // }
        }
        strRTCNType = QString::fromLocal8Bit("%0").arg("UIM242:S1->下降沿");
    }
    break;
    case 113 + (1<<7):
    {
        if(fsUim->isFocusId(dwCanNodeId)){
            // if(fsUim->canFocusResetMark == 1){
            //     fsUim->canFocusResetMark++;
            //     retInfo(QString("对焦复位-%0").arg(fsUim->canFocusResetMark));
            // }
        }
        strRTCNType = QString::fromLocal8Bit("%0").arg("UIM242:S1->上升沿");
    }
    break;
    case 114:
    {
        strRTCNType = QString::fromLocal8Bit("%0").arg("UIM242:S2->下降沿");
    }
    break;
    case 114 + (1<<7):
    {
        strRTCNType = QString::fromLocal8Bit("%0").arg("UIM242:S2->上升沿");
    }
    break;
    case 115:
    {
        strRTCNType = QString::fromLocal8Bit("%0").arg("UIM242:S3->下降沿");
    }
    break;
    case 115 + (1<<7):
    {
        strRTCNType = QString::fromLocal8Bit("%0").arg("UIM242:S3->上升沿");
    }
    break;
    case 117:
    {
        strRTCNType = QString::fromLocal8Bit("%0").arg("UIM242:STP");
        if(fsUim->getFocusMoveStep()==0){
            isSend = false;
        }
    }
    break;
    case 117 + (1<<7):
    {
        strRTCNType = QString::fromLocal8Bit("%0").arg("UIM242:STP");
    }
    break;
    case 118:
    {
        strRTCNType = QString::fromLocal8Bit("%0").arg("UIM242:ORG");
    }
    break;
    case 90:
    {
        if( pRtcnMsgObj->Data[0]%2 == 0)
        {
            strRTCNType = QString::fromLocal8Bit("P%0L").arg((pRtcnMsgObj->Data[0]+1)/2);
        }
        else
        {
            strRTCNType = QString::fromLocal8Bit("P%0H").arg((pRtcnMsgObj->Data[0]+1)/2);
        }
    }
    default:
        break;
    }
    strRTCNType += QString(" retCode=%0 nodeId=%1 devIndex=%2 isKeyCanMove=%3 getFocusMoveStep=%4 %5")
                       .arg(iRCW).arg(dwCanNodeId).arg(dwDevIndex).arg(isKeyCanMove).arg(fsUim->getFocusMoveStep()).arg(isSend);
    retInfo(strRTCNType);
    if(isSend){
        emit SendRTCNMsg(strRTCNType,iRCW,dwCanNodeId);
    }
}

//参数设置
void MainWindow::on_pushButtonSetup_clicked()
{
    showBottomCanStatus("uim设置");
    UIMsetup *set = new UIMsetup(nullptr, fsConf, fsUim);
    set->setWindowModality(Qt::ApplicationModal);
    if(is4KScreen()){
        set->setWin(fsConf->designVar.UiSetupWindowWidth4K,fsConf->designVar.UiSetupWindowHeight4K);
    }else{
        set->setWin(fsConf->designVar.UiSetupWindowWidth,fsConf->designVar.UiSetupWindowHeight);
    }
    connect(set, SIGNAL(uimFlush()),this,SLOT(recvUimFlush()));
    connect(set, SIGNAL(uimSave()),this,SLOT(recvUimSave()));
    set->show();

}

void MainWindow::recvUimFlush(void){

    canCallback();
    showBottomCanStatus(fsConf->uimVar.UIMStartTitle);
    flushCanState();
    initUimScreen();
}

void MainWindow::recvUimSave(void){
    retInfo("recvUimSave");
    ui->spinBoxRightRate->setValue(fsConf->uimVar.UIMCanRateRight);
    ui->spinBoxAutoPhotoCanRate->setValue(fsConf->uimVar.UIMCanRatePhoto);
    ui->checkBoxEncodeStop->setChecked(fsConf->uimVar.UIMCanEncodeStop);
}


//选择当前设备
void MainWindow::on_comboBoxDevice_currentIndexChanged(int index)
{
    if(!isMvs())
        return;
    retInfo(QString("mvs device %0").arg(index));

}

//设置停止位置
bool MainWindow::setCanFar(int node,int rate,int step)
{
    //判断是否有停止位，如果有，设置绝对位置
    int pos=0,curPos=0,farPos=0;
    if(fsUim->isFocusId(node)){
        farPos = fsConf->uimVar.UIMCanFocusFar;
        curPos = fsUim->getFocusPos();
    }
    if(farPos>0){
        if((curPos+step)>farPos){
            pos = farPos;
        }
    }
    if(pos>0){
        fsUim->canSetSPD(node,rate);
        fsUim->canSetPOS(node,pos);
        retInfo(QString("%0 置停止位 %1 %2").arg(node).arg(rate).arg(pos));
        return true;
    }
    return false;
}

//电机移动
void MainWindow::canMove(const QString msg,const bool mode,const int direction){
    showBottomCanStatus(msg);
    bool isLimit = false;
    isKeyCanMove=mode;
    //Focus
    if((bool)fsConf->uimVar.UIMCanFocusMode!=mode)return;
    if(!fsUim->isFocusId())return;
    if(mode){
        isLimit = getCanFocusLimitPos(direction);
        if(!isLimit){
            //持续移动
            fsUim->canFocusEna();
            fsUim->canSetSTP(fsUim->getFocusId(),0);
            fsUim->canSetSPD(fsUim->getFocusId(),direction*fsConf->uimVar.UIMCanRateFocus);
            fsUim->setCanFocusMoveDirection(direction);
        }
    }else{
        //相对位置
        if(fsUim->getCanFocusMoveDirection()!=0)return;
        if(fsConf->uimVar.Debug==0&&setCanFar(fsUim->getFocusId(),fsConf->uimVar.UIMCanRateFocus,fsConf->uimVar.UIMCanStepFocus))return;
        fsUim->canFocusEna();
        fsUim->canSetSPD(fsUim->getFocusId(),fsConf->uimVar.UIMCanRateFocus);
        fsUim->canSetSTP(fsUim->getFocusId(),direction*fsConf->uimVar.UIMCanStepFocus);
    }
    retInfo(QString("CanMove %0 %1").arg(mode).arg(isLimit));
    if(mode&&!isLimit){
        //电机移动定时器
        canMoveTimer->start(fsConf->uimVar.UIMCanTimer);
        curCanMoveTimer = QDateTime::currentMSecsSinceEpoch();
    }
    flushCanState();
}

void MainWindow::canMovePos(const QString msg,const int locate,int rate){
    showBottomCanStatus(msg);
    isKeyCanMove=false;
    retInfo(QString("canMovePos %0 %1 %2").arg(msg).arg(locate).arg(fsUim->getCanFocusMoveDirection()));
    int sp=0;
    if(rate>0)sp=rate;
    //Focus
    flushCanState();
    if(!fsUim->isFocusId())return;
    if(fsUim->getCanFocusMoveDirection()!=0)return;
    if(fsConf->uimVar.Debug==0&&setCanFar(fsUim->getFocusId(),fsConf->uimVar.UIMCanRateFocusLocate,fsConf->uimVar.UIMCanStepFocus))return;
    fsUim->canFocusEna();
    if(sp==0)sp = fsConf->uimVar.UIMCanRateFocusLocate;
    if(sp>0){
        fsUim->canSetSPD(fsUim->getFocusId(),sp);
        fsUim->canSetPOS(fsUim->getFocusId(),locate);
        canMoveTimer->start(fsConf->uimVar.UIMCanTimer);
        curCanMoveTimer = QDateTime::currentMSecsSinceEpoch();
    }
}

void MainWindow::canMoveStep(const QString msg,const int step,int rate){
    showBottomCanStatus(msg);
    retInfo(QString("%0 %1").arg(msg).arg(step));
    int sp=0;
    if(rate>0)sp=rate;
    //Focus
    if(!fsUim->isFocusId())return;
    if(fsUim->getCanFocusMoveDirection()!=0)return;
    if(fsConf->uimVar.Debug==0&&setCanFar(fsUim->getFocusId(),fsConf->uimVar.UIMCanRateFocus,fsConf->uimVar.UIMCanStepFocus))return;
    fsUim->canFocusEna();
    if(sp==0)sp = fsConf->uimVar.UIMCanRateFocus;
    if(sp>0){
        fsUim->canSetSPD(fsUim->getFocusId(),sp);
        fsUim->canSetSTP(fsUim->getFocusId(),step);
    }
    flushCanState();
}

//电机停止
void MainWindow::canStopMove(void){
    isKeyCanMove=false;
    //Focus
    if(!fsUim->isFocusId())return;
    fsUim->canSetSPD(fsUim->getFocusId(),0);
    fsUim->setCanFocusMoveDirection(0);
    // fsUim->canSetSTP(fsUim->getFocusId(),0);
    //定时停止
    canMoveTimer->stop();
    flushCanState();
}

//调上
void MainWindow::on_pushButtonFocusUp_clicked()
{
    canMove("调整镜头调上",0,1);
}


void MainWindow::on_pushButtonFocusUp_pressed()
{
    canMove("调整镜头调上连续",1,1);
}


void MainWindow::on_pushButtonFocusUp_released()
{
    canStopMove();
}

//调下
void MainWindow::on_pushButtonFocusDown_clicked()
{
    canMove("调整镜头调下",0,-1);
}


void MainWindow::on_pushButtonFocusDown_pressed()
{
    canMove("调整镜头调下连续",1,-1);
}


void MainWindow::on_pushButtonFocusDown_released()
{
    canStopMove();
}

//置位
void MainWindow::on_pushButtonFocusSet_clicked()
{
    canMovePos("focus 置位",fsConf->uimVar.UIMCanStepFocusLocate);
}

//复位

void MainWindow::on_pushButtonFocusReset_clicked()
{
    if(fsConf->uimVar.UIMCanStepFocusLocate != fsUim->getFocusPos()){
        fsConf->uimVar.UIMCanStepFocusLocate = fsUim->getFocusPos();
        fsConf->saveConfigUimReset();
    }
    ui->pushButtonFocusSet->setEnabled(fsUim->isCanSet(fsUim->getFocusId()));
}

//走片
void MainWindow::on_pushButtonRightMove_clicked()
{
    if(!fsUim->isRightId())return;
    if(fsUim->isRightMove()){
        showBottomCanStatus("停止");
        fsUim->canRightOff();
        ui->pushButtonRightMove->setText(fsConf->uimVar.UIMRightMoveTitle[0]);
    }else{
        showBottomCanStatus(QString("走片 %0").arg(fsConf->uimVar.UIMCanRateRight));
        fsUim->canRightEna();
        ui->pushButtonRightMove->setText(fsConf->uimVar.UIMRightMoveTitle[1]);
        // fsUim->canSetOrg(fsUim->getRightId());
        fsUim->canSetSTP(fsUim->getRightId(),0);
        fsUim->canSetSPD(fsUim->getRightId(),fsConf->uimVar.UIMCanRateRight);
    }
}

//走片速度
void MainWindow::on_spinBoxRightRate_valueChanged(int arg1)
{
    if(arg1 != fsConf->uimVar.UIMCanRateRight){
        fsConf->uimVar.UIMCanRateRight = arg1;
        fsConf->saveConfigUimPhoto();
    }
    if(fsUim->isRightMove()){
        retInfo(QString("right rate %0").arg(fsConf->uimVar.UIMCanRateRight));
        fsUim->canSetSPD(fsUim->getRightId(),fsConf->uimVar.UIMCanRateRight);
    }
}

//自拍速度
void MainWindow::on_spinBoxAutoPhotoCanRate_valueChanged(int arg1)
{
    if(arg1 != fsConf->uimVar.UIMCanRatePhoto){
        fsConf->uimVar.UIMCanRatePhoto = arg1;
        fsConf->saveConfigUimPhoto();
    }
    if(fsUim->isRightMove()){
        retInfo(QString("right autoPhoto rate %0").arg(fsConf->uimVar.UIMCanRatePhoto));
        fsUim->canSetSPD(fsUim->getRightId(),fsConf->uimVar.UIMCanRatePhoto);
    }
}

//自拍
void MainWindow::on_checkBoxAutoPhoto_toggled(bool checked)
{
    bAutoPhoto = checked;
    initUimScreen();

    // ui->pushButtonPhotograph->setEnabled(!bAutoPhoto);
    if(bAutoPhoto){
        //自拍
        showBottomMvsStatus("自拍");
        if(!fsMvs->isGrabbing()){
            //MVS开始采集
            on_pushButtonStartAcquisition_clicked();
        }
        //设置电机
        fsUim->canRightEna();
        // fsUim->canSetOrg(fsUim->getRightId());
        fsUim->canSetSTP(fsUim->getRightId(),0);
        fsUim->canSetSPD(fsUim->getRightId(),fsConf->uimVar.UIMCanRatePhoto);
    }else{
        //停止电机
        showBottomMvsStatus("停拍");
        fsUim->canRightOff();
        if(fsMvs->isGrabbing()){
            //MVS停止采集
            on_pushButtonStartAcquisition_clicked();
        }
    }
}

//自停
void MainWindow::on_checkBoxEncodeStop_toggled(bool checked)
{
    if(checked != (bool)fsConf->uimVar.UIMCanEncodeStop){
        fsConf->uimVar.UIMCanEncodeStop = checked;
        fsConf->saveConfigUimPhoto();
    }
}

//保存格式
void MainWindow::on_comboBoxSaveFormat_currentIndexChanged(int index)
{
    ui->spinBoxSavePara->setEnabled(index>0);
    int para=0;
    switch(index){
    case 1:
        if(fsConf->designVar.Para >= 50 && fsConf->designVar.Para <= 100){
            para = fsConf->designVar.Para;
        }else{
            para = 100;
        }
        ui->spinBoxSavePara->setMinimum(50);
        ui->spinBoxSavePara->setSingleStep(10);
        ui->spinBoxSavePara->setMaximum(100);
        break;
    case 2:
        para = 1;
        ui->spinBoxSavePara->setMinimum(1);
        ui->spinBoxSavePara->setSingleStep(1);
        ui->spinBoxSavePara->setMaximum(1);
        break;
    case 3:
        if(fsConf->designVar.Para >= 3 && fsConf->designVar.Para <= 9){
            para = fsConf->designVar.Para;
        }else{
            para = 9;
        }
        ui->spinBoxSavePara->setMinimum(3);
        ui->spinBoxSavePara->setSingleStep(1);
        ui->spinBoxSavePara->setMaximum(9);
        break;
    default:
        ui->spinBoxSavePara->setMinimum(0);
        ui->spinBoxSavePara->setMaximum(0);
        break;
    }
    ui->spinBoxSavePara->setValue(para);
    if(index != fsConf->designVar.SaveFormat || para != fsConf->designVar.Para){
        fsConf->designVar.SaveFormat = index;
        fsConf->designVar.Para = para;
        fsConf->saveConfigDesignPara();
    }
}

//格式参数
void MainWindow::on_spinBoxSavePara_valueChanged(int arg1)
{
    if(arg1 != fsConf->designVar.Para){
        fsConf->designVar.Para = arg1;
        fsConf->saveConfigDesignPara();
    }
}

//保存图像横向/纵向
void MainWindow::on_checkBoxSaveHeight_toggled(bool checked)
{
    if((int)checked != fsConf->designVar.SaveHeight){
        fsConf->designVar.SaveHeight = checked;
        fsConf->saveConfigDesignPara();
    }
}

//DPI
void MainWindow::on_comboBoxSaveDpi_currentTextChanged(const QString &arg1)
{
    if(arg1.toInt() != fsConf->designVar.SaveDPI){
        fsConf->designVar.SaveDPI = arg1.toInt();
        fsConf->saveConfigDesignPara();
    }
}

void __stdcall MVSIMAGECALLBACK(unsigned char *pData , MV_FRAME_OUT_INFO_EX* pFrameInfo, void* pUser)
{
    MainWindow *pWin = (MainWindow *)pUser;
    if(pFrameInfo && pWin){
        MVS_FRAME_OUT out;
        out.Width = pFrameInfo->nWidth;
        out.Height = pFrameInfo->nHeight;
        out.FrameNum = pFrameInfo->nFrameNum;
        out.ErrorNums = pFrameInfo->nUnparsedChunkNum;
        out.LostNums = pFrameInfo->nLostPacket;
        out.FrameByteLen = pFrameInfo->nFrameLen;
        out.TimeStamp = pFrameInfo->nHostTimeStamp;
        out.ImageFormat = getImageFormat(pFrameInfo->enPixelType);
        out.FrameCounter = pFrameInfo->nFrameCounter;
        out.TriggerIndex = pFrameInfo->nTriggerIndex;

        pWin->mvsFrameCallback(pData, &out);
    }
}

void __stdcall MVSEVENTCALLBACK(MV_EVENT_OUT_INFO * pEventInfo, void* pUser)
{
    MainWindow *pWin = (MainWindow *)pUser;
    if (pEventInfo)
    {
        MVS_EVENT_OUT out;

        __int64 nBlockId = pEventInfo->nBlockIdHigh;
        out.BlockId = (nBlockId << 32) + pEventInfo->nBlockIdLow;

        __int64 nTimestamp = pEventInfo->nTimestampHigh;
        out.TimeStamp = (nTimestamp << 32) + pEventInfo->nTimestampLow;

        pWin->mvsEventCallback(&out);
    }
}

//初始预览-
void MainWindow::initPreview(void){
    if(isInitPreview){
        //采集状态
        clearPreview();
        return;
    }
    frameImageZoomMutex->lock();
    curPreviewPos = 0;
    int rows,cols,type;
    rows = fsMvs->getPara().Width;
    cols = fsMvs->getPara().Height*fsConf->mvsVar.MvsSaveFrameNums;
    type = (fsMvs->getPara().ImageFormat == 0) ? CV_8UC1:CV_8UC3;

    curPreviewImage = cv::Mat::zeros(cv::Size(rows, cols), type);
    isInitPreview = true;
    frameImageZoomMutex->unlock();
}

//释放预览
void MainWindow::relePreview(void){
    if(isInitPreview){
        curPreviewImage.release();
        isInitPreview = false;
        curPreviewPos = 0;
    }
}

void MainWindow::clearPreview(void){
    retInfo("clearPreview");
    if(!isInitPreview){
        return;
    }
    //初始数据
    frameImageZoomMutex->lock();
    curPreviewPos = 0;
    cv::Scalar color = (fsMvs->getPara().ImageFormat == 0) ? cv::Scalar(200):cv::Scalar(200,200,200);
    cv::Mat dst = cv::Mat(curPreviewImage.rows, curPreviewImage.cols, curPreviewImage.type(), color);
    dst.copyTo(curPreviewImage);
    frameImageZoomMutex->unlock();
}

//增加预览
void MainWindow::addPreview(const cv::Mat src){
    if(!isInitPreview){
        return;
    }
    frameImageZoomMutex->lock();
    cv::Rect rect = cv::Rect(0, src.rows*curPreviewPos, src.cols, src.rows);
    src.copyTo(curPreviewImage(rect));
    // retInfo(QString("addPreview %0 %1 %2").arg(curPreviewPos).arg(src.rows).arg(src.cols));
    curPreviewPos++;
    if(ui->checkBoxOneFrame->isChecked()){
        //单帧显示
        curFrameImage = src.clone();
    }else{
        //多帧显示
        curFrameImage = curPreviewImage.clone();
    }
    frameImageZoomMutex->unlock();
    flushFrame();
    if(curPreviewPos==fsConf->mvsVar.MvsSaveFrameNums){
        saveImageThread->AddImg(curPreviewImage.clone());
        clearPreview();
    }
    showBottomInfo(QString("%0 %1 %2").arg(curPreviewPos).arg(saveImageThread->getImageList()).arg(saveImageThread->getLogList()));
}

//预览存储
void MainWindow::savePreview(void){
    if(!isInitPreview){
        return;
    }

}

void MainWindow::recvFrameImageZoom(int zoom,int x,int y){
    retInfo(QString("recvFrameImageZoom %0 %1 pos %2 %3").arg(zoom).arg(curFrameImageZoom).arg(x).arg(y));
    int z = curFrameImageZoom;
    z += zoom/fsConf->designVar.MouseWheelStep;
    ui->spinBoxImageZoom->setValue(z);
    if(z == curFrameImageZoom){
        return;
    }
    if(z<0){
        return;
    }
    if(z>=fsConf->designVar.FrameImageZoomMax){
        return;
    }
    curFrameImageZoom = z;
    curFrameImagePosX = x;
    curFrameImagePosY = y;
    ui->labelFrameImage->zoom = z;
}

void MainWindow::recvResultImageZoom(int zoom,int x,int y){
    retInfo(QString("recvResultImageZoom %0 %1 pos %2 %3").arg(zoom).arg(curResultImageZoom).arg(x).arg(y));
    int z = curResultImageZoom;
    z += zoom/fsConf->designVar.MouseWheelStep;
    ui->spinBoxResultZoom->setValue(z);
    if(z == curResultImageZoom){
        return;
    }
    if(z<0){
        return;
    }
    if(z>=fsConf->designVar.ResultImageZoomMax){
        return;
    }
    curResultImageZoom = z;
    curResultImagePosX = x;
    curResultImagePosY = y;
    ui->labelResultImage->zoom = z;
    flushResult();
}

void MainWindow::recvFrameImageMove(int x,int y){
    curFrameImagePosX -= x;
    curFrameImagePosY -= y;
    if(curFrameImagePosX<0){
        curFrameImagePosX = 0;
    }
    if(curFrameImagePosY<0){
        curFrameImagePosY = 0;
    }
    retInfo(QString("recvFrameImageMove %0 %1 pos %2 %3")
                .arg(x).arg(y).arg(curFrameImagePosX).arg(curFrameImagePosY));
}

void MainWindow::recvResultImageMove(int x,int y){
    curResultImagePosX -= x;
    curResultImagePosY -= y;
    if(curResultImagePosX<0){
        curResultImagePosX = 0;
    }
    if(curResultImagePosY<0){
        curResultImagePosY = 0;
    }
    retInfo(QString("recvResultImageMove %0 %1 pos %2 %3")
                .arg(x).arg(y).arg(curResultImagePosX).arg(curResultImagePosY));
    flushResult();
}

//显示当前缓存图片
void MainWindow::flushFrame(void){
    if(!isInitPreview){
        //非采集
        ui->labelFrameImage->setPixmap(QPixmap());
        return;
    }
    retInfo("flushFrame");
    frameImageZoomMutex->lock();
    showBottomResult(QString("%0-%1").arg(curFrameImage.cols).arg(curFrameImage.rows));
    cv::Mat image;
    if(curFrameImage.cols<curFrameImage.rows){
        cv::rotate(curFrameImage.clone(),image,cv::ROTATE_90_COUNTERCLOCKWISE);
    }else{
        image = curFrameImage.clone();
    }

    if(curFrameImageZoom>0){
        //放大
        float zoom = float(10+curFrameImageZoom)/10.0;
        cv::Mat src = matResize1(image, winFrameWidth*zoom, winFrameHeight*zoom);
        //位置
        int posX=curFrameImagePosX,posY=curFrameImagePosY;
        cv::Rect box;
        if((posX+winFrameWidth)>=src.cols){
            posX = src.cols - winFrameWidth;
        }
        if((posY+winResultHeight)>=src.rows){
            posY = src.rows - winFrameHeight;
        }
        box.x = posX;
        box.y = posY;
        box.width = winFrameWidth;
        box.height = winFrameHeight;
        image = src(box);
        retInfo(QString("flush frame %0 %1 box %2 %3 %4 %5")
                    .arg(image.cols).arg(image.rows)
                    .arg(box.x).arg(box.y).arg(box.width).arg(box.height));
    }else{
        float scale=1.0;
        image = matResize(image, winFrameWidth, winFrameHeight,scale);
    }
    ui->labelFrameImage->setPixmap(cvMatToQPixmap(image));
    frameImageZoomMutex->unlock();
}

//海康事件回调
void MainWindow::mvsEventCallback(MVS_EVENT_OUT *pEventOut)
{
    retInfo(QString("mvs event callback %0 %1").arg(pEventOut->BlockId).arg(pEventOut->TimeStamp));
}

//海康图像回调
void MainWindow::mvsFrameCallback(unsigned char *pImageData, MVS_FRAME_OUT *pFrameOut){
    if(pImageData){
        // retInfo(QString("mvs callback imageData : width=%0 height=%1 type=%2 %3 %4 time=%5")
        //             .arg(pFrameOut->Width).arg(pFrameOut->Height).arg(pFrameOut->ImageFormat)
        //             .arg(pFrameOut->FrameNum).arg(pFrameOut->FrameByteLen).arg(pFrameOut->TimeStamp));
        if(!saveImageMutex->tryLock()){
            return;
        }
        if(bAutoPhoto){
            //显示编码信息
            //判断编码，是否自拍停止
            flushAutoPhotoInfo();
            if(ui->checkBoxEncodeStop->isChecked() && fsMvs->curFrameEncodeCounter == 0){
                //停止自拍
                ui->checkBoxAutoPhoto->setChecked(false);
                return;
            }
        }
        fsMvs->setPara(pFrameOut->FrameNum, pFrameOut->ErrorNums, pFrameOut->LostNums);
        showTopImageNums();
        showTopErrorNums();
        showTopLostNums();
        if(fsConf->funcVar.Log){
            //记录每帧日志
            QString info = QString("mvs frame %0: %1x%2 byte=%3 %4 %5 %6 can Encode=%7 Pos=%8")
                               .arg(pFrameOut->FrameNum).arg(pFrameOut->Width).arg(pFrameOut->Height)
                               .arg(pFrameOut->FrameByteLen).arg(pFrameOut->FrameCounter).arg(pFrameOut->TriggerIndex)
                               .arg(pFrameOut->TimeStamp)
                               .arg(fsMvs->curFrameEncodeCounter).arg(fsUim->curFramePosCounter);
            saveImageThread->AddLog(info);
        }
        cv::Mat src;
        if(pFrameOut->ImageFormat){
            RGB2BGR(pImageData, pFrameOut->Width, pFrameOut->Height);
            src = cv::Mat(pFrameOut->Height, pFrameOut->Width, CV_8UC3, pImageData);
        }else{
            src = cv::Mat(pFrameOut->Height, pFrameOut->Width, CV_8UC1, pImageData);
        }
        //海康函数-显示一帧
        //        MV_DISPLAY_FRAME_INFO stDisplayInfo = {0};
        //        stDisplayInfo.hWnd = winPreviewWnd;
        //        stDisplayInfo.pData = pImageData;
        //        stDisplayInfo.nDataLen = nDataLen;
        //        stDisplayInfo.nWidth = nWidth;
        //        stDisplayInfo.nHeight = nHeight;
        //        stDisplayInfo.enPixelType = pixelType;
        //        fsMvs->DisplayOneFrame(&stDisplayInfo);
        //加入缓冲一帧
        addPreview(src);
        // while(true){
        //     if(bImagePartEnlarge){
        //         if(enlargeWindow->screenImageMutex->tryLock()){
        //             enlargeWindow->curEnlargeImage = src.clone();
        //             enlargeWindow->isShow= true;
        //             enlargeWindow->screenImageMutex->unlock();
        //             enlargeWindow->update();
        //         }
        //     }
        //     if(isAddScan()&&ui->checkBoxScanContour->isChecked()){
        //         scanPreviewContour(src);
        //         break;
        //     }
        //     curFullImage = src.clone();
        //     break;
        // }
        saveImageMutex->unlock();
    }
}

//开始采集
void MainWindow::on_pushButtonStartAcquisition_clicked()
{
    //MVS
    if(!fsMvs->isOpen()){
        return;
    }
    if(fsMvs->isGrabbing()){
        showBottomAlarm("关闭采集");
        saveImageThread->stop();
        saveImageThread->wait();
        QThread::sleep(1);
        delete saveImageThread;
        saveImageThread = nullptr;
        QObject::disconnect(ui->labelFrameImage, SIGNAL(imageMove(int,int)), this, SLOT(recvFrameImageMove(int,int)));
        QObject::disconnect(ui->labelFrameImage, SIGNAL(imageZoom(int,int,int)), this, SLOT(recvFrameImageZoom(int,int,int)));

        fsMvs->stopGrabbing();
        // fsMvs->RegisterImageCallBack(nullptr,nullptr);
        fsMvs->RegisterEventCallBack(nullptr,nullptr);
    }else{
        showBottomAlarm("开始采集");
        curResultFileNum = 1;
        initPreview();
        // flushFrame();
        if(curResultFileList.count()){
            //清除文件
            clearResultFile();
        }
        saveImageThread = new SaveThread(nullptr, fsConf, curResultDirList[curResultDirIndex]);
        QObject::connect(saveImageThread, SIGNAL(saveFile(QString)), this, SLOT(recvSaveThreadFile(QString)));
        saveImageThread->start();
        //
        QObject::connect(ui->labelFrameImage, SIGNAL(imageMove(int,int)), this, SLOT(recvFrameImageMove(int,int)));
        QObject::connect(ui->labelFrameImage, SIGNAL(imageZoom(int,int,int)), this, SLOT(recvFrameImageZoom(int,int,int)));
        fsMvs->getEncode();
        // fsMvs->RegisterEventCallBack(MVSEVENTCALLBACK,this);
        fsMvs->RegisterImageCallBack(MVSIMAGECALLBACK,this);
        fsMvs->startGrabbing();
    }
    // flushMvsState();
    initMvsScreen();
    flushPushButton(ui->pushButtonStartAcquisition,fsMvs->isGrabbing());
    if(fsMvs->isGrabbing()){
        //关闭
        showBottomMvsStatus(QString("%0").arg(saveImageThread->threadId));
        ui->pushButtonStartAcquisition->setText(QString("%0").arg(fsConf->mvsVar.MvsCloseAcquisition));
    }else{
        //启动
        showBottomMvsStatus("");
        ui->pushButtonStartAcquisition->setText(QString("%0").arg(fsConf->mvsVar.MvsStartAcquisition));
    }
}

//图像格式
void MainWindow::on_comboBoxImageFormat_currentIndexChanged(int index)
{
    if(index == fsMvs->getPara().ImageFormat){
        return;
    }
    bool ret = fsMvs->setImageFormat(index);
    retInfo(QString("mvsImageFormat %0=%1").arg(index).arg(ret));
}

//图像宽度
void MainWindow::on_spinBoxMvsWidth_valueChanged(int arg1)
{
    if(arg1 == fsMvs->getPara().Width){
        return;
    }
    bool ret = fsMvs->setWidth(arg1);
    retInfo(QString("setWidth %0=%1").arg(arg1).arg(ret));
}

//图像高度
void MainWindow::on_spinBoxMvsHeight_valueChanged(int arg1)
{
    if(arg1 == fsMvs->getPara().Height){
        return;
    }
    bool ret = fsMvs->setHeight(arg1);
    retInfo(QString("setHeight %0=%1").arg(arg1).arg(ret));
}

//行频设置：图像拉伸则降行频，压缩增行频
void MainWindow::on_spinBoxMvsLineRate_valueChanged(int arg1)
{
    if(arg1 == fsMvs->getPara().AcquisitionLineRate){
        return;
    }
    bool ret = fsMvs->setLineRate(arg1);
    retInfo(QString("setLineRate %0=%1").arg(arg1).arg(ret));
}

//行频使能
void MainWindow::on_checkBoxMvsLineRate_toggled(bool checked)
{
    if(checked == fsMvs->getPara().AcquisitionLineRateEnable){
        return;
    }
    bool ret = fsMvs->setLineRateEnable(checked);
    retInfo(QString("setLineRateEnable %0=%1").arg(checked).arg(ret));
}

//曝光时间
void MainWindow::on_doubleSpinBoxMvsExposure_valueChanged(double arg1)
{
    if(arg1 == fsMvs->getPara().ExposureTime){
        return;
    }
    bool ret = fsMvs->setExposureTime(arg1);
    retInfo(QString("setExposureTime %0=%1").arg(getNumber(arg1)).arg(ret));
}

//触发使能
void MainWindow::on_checkBoxTriggerMode_toggled(bool checked)
{
    if(checked == fsMvs->getPara().TriggerMode){
        return;
    }
    bool ret = fsMvs->setTriggerMode(checked);
    retInfo(QString("setTriggerMode %0=%1").arg(getNumber(checked)).arg(ret));
}

//前置：图像拉伸则增大
void MainWindow::on_spinBoxPreDivider_valueChanged(int arg1)
{
    if(arg1 == fsMvs->getPara().PreDivider){
        return;
    }
    bool ret = fsMvs->setPreDivider(arg1);
    retInfo(QString("setPreDivider %0=%1").arg(getNumber(arg1)).arg(ret));
}

//倍频：图像压缩则增大
void MainWindow::on_spinBoxMultiplier_valueChanged(int arg1)
{
    if(arg1 == fsMvs->getPara().Multiplier){
        return;
    }
    bool ret = fsMvs->setMultiplier(arg1);
    retInfo(QString("setMultiplier %0=%1").arg(getNumber(arg1)).arg(ret));

}

//后置：图像拉伸则增大
void MainWindow::on_spinBoxPostDivider_valueChanged(int arg1)
{
    if(arg1 == fsMvs->getPara().PostDivider){
        return;
    }
    bool ret = fsMvs->setPostDivider(arg1);
    retInfo(QString("setPostDivider %0=%1").arg(getNumber(arg1)).arg(ret));
}

//平场使能
void MainWindow::on_checkBoxPRNUCEnable_toggled(bool checked)
{
    if(checked == fsMvs->getPara().PRNUCROIEnable){
        return;
    }
    // bool ret = fsMvs->setTriggerMode(checked);
    // retInfo(QString("setTriggerMode %0=%1").arg(getNumber(checked)).arg(ret));
}


//选择保存位置

void MainWindow::on_pushButtonSelectResultPath_clicked()
{
    QString path = QFileDialog::getExistingDirectory(this,
                                                     " 选择帧图片保存目录 ",
                                                     QString(fsConf->listVar.SaveResultPath));
    if(path.isEmpty())return;
    ui->lineEditResultSavePath->setText(path);
    if(path.compare(fsConf->listVar.SaveResultPath)){
        //修改存储目录
        retInfo("select result Path");
        qStrToCstr(path,fsConf->listVar.SaveResultPath,sizeof(fsConf->listVar.SaveResultPath));
        fsConf->saveConfigListSave();
        on_pushButtonDirFlush_clicked();
        flushProc();
    }
}


void MainWindow::on_pushButtonSelectImagePath_clicked()
{
    QString path = QFileDialog::getExistingDirectory(this,
                                                     " 选择处理图片保存目录 ",
                                                     QString(fsConf->listVar.SaveImagePath));
    if(path.isEmpty())return;
    ui->lineEditImageSavePath->setText(path);
    if(path.compare(fsConf->listVar.SaveImagePath)){
        //修改存储目录
        retInfo("select image Path");
        qStrToCstr(path,fsConf->listVar.SaveImagePath,sizeof(fsConf->listVar.SaveImagePath));
        fsConf->saveConfigListSave();
    }
}

void MainWindow::recvSaveThreadFile(QString file){
    //存储线程文件
    QFileInfo fileInfo(file);
    if(fileInfo.exists()&&fileInfo.isFile()){
        retInfo(QString("recvSaveThreadFile %0").arg(file));
        addResultFileList(fileInfo);
    }
}

void MainWindow::addResultFileList(QFileInfo info){
    QListWidgetItem *item;

    curResultFileList.append(info.absoluteFilePath());
    // 列表
    item = new QListWidgetItem(info.fileName());
    getFilename(info.baseName(),curResultFileNo);
    ui->listWidgetResultFile->addItem(item);
    ui->labelResultInfo->setText(QString("采集 %0").arg(curResultFileList.count()));
}

void MainWindow::delResultFileListItem(int index){
    retInfo(QString("delResultFileListItem %0").arg(index));
    ui->listWidgetResultFile->blockSignals(true);
    if(index<0){
        QListWidgetItem *delItem;
        while(ui->listWidgetResultFile->count()){
            delItem = ui->listWidgetResultFile->takeItem(0);
            ui->listWidgetResultFile->removeItemWidget(delItem);
            delete delItem;
        }
    }else{
        QListWidgetItem *delItem;
        delItem = ui->listWidgetResultFile->takeItem(curResultFileIndex);
        ui->listWidgetResultFile->removeItemWidget(delItem);
        delete delItem;
    }
    ui->listWidgetResultFile->update();
    ui->listWidgetResultFile->blockSignals(false);
}

//刷新目录文件列表
void MainWindow::flushResultFileList(const QString curFile){
    retInfo(QString("flushResultFileList %0").arg(curFile));
    // 初始化
    curResultFileIndex = -1;
    curResultFileNo[0] = 0;
    curResultFileNo[1] = 0;
    curResultFileList.clear();
    isResultImage = false;
    ui->spinBoxResultImageNum->setValue(0);
    ui->spinBoxProcImageNum->setValue(0);
    ui->labelResultImageInfo->setText("");
    ui->labelProcImageInfo->setText("");
    showResult();
    //删除所有项目
    delResultFileListItem(-1);
    // 设置当前目录
    QFileInfoList fileList;
    QFileInfo info;
    QDir dir(curResultDirList[curResultDirIndex]);
    qStrToCstr(dir.dirName(),fsConf->listVar.ListCurDir,sizeof(fsConf->listVar.ListCurDir));
    // 读取目录文件
    dir.setNameFilters(QString(fsConf->listVar.ListFilter).split(','));
    fileList = dir.entryInfoList(QDir::NoDot|QDir::NoDotAndDotDot|QDir::Files,QDir::Name);
    showBottomInfo(QString("read %0 file lst").arg(curResultDirList[curResultDirIndex]));
    retInfo(QString("read dir index %0 count %1").arg(curResultDirIndex).arg(fileList.count()));
    if(fileList.count()==0){
        return;
    }
    ui->listWidgetResultFile->setViewMode(QListView::ListMode);
    int index = 0;
    foreach(info,fileList){
        // retInfo(QString("fileList %0 %1").arg(curResultFileList.count()).arg(info.fileName()));
        if(!curFile.isEmpty()&&curFile.compare(info.fileName(),Qt::CaseInsensitive) == 0){
            index = curResultFileList.count();
        }
        addResultFileList(info);
    }
    //文件索引
    curResultFileIndex = index;
    retInfo(QString("read %0 %1 %2")
                .arg(curResultDirList[curResultDirIndex])
                .arg(curResultFileList.count()).arg(curResultFileIndex));
}

//选择当前目录
void MainWindow::on_comboBoxResultDir_currentIndexChanged(int index)
{
    if(curResultDirIndex > 0 && index > 0 && curResultDirIndex != index){
        fsConf->listVar.ListCurName[0]=0;
    }
    curResultDirIndex = index;
    retInfo(QString("current DirList index %0 %1 fileIndex %2").arg(curResultDirIndex).arg(fsConf->listVar.ListCurDir).arg(curResultFileIndex));
    if(index<0){
        return;
    }
    ui->comboBoxResultDir->setEnabled(false);
    flushResultFileList(fsConf->listVar.ListCurName);
    ui->comboBoxResultDir->setEnabled(true);
}

//刷新当前目录
void MainWindow::on_pushButtonDirFlush_clicked()
{
    retInfo("on_pushButtonDirFlush_clicked");
    //初始化
    // ui->comboBoxResultDir->blockSignals(true);
    ui->comboBoxResultDir->clear();
    // ui->comboBoxResultDir->blockSignals(false);

    ui->listWidgetResultFile->blockSignals(true);
    ui->listWidgetResultFile->clear();
    ui->listWidgetResultFile->blockSignals(false);

    curResultDirList.clear();
    curResultFileList.clear();
    curResultDirIndex = -1;
    isResultImage = false;
    //查询
    QString curDir;
    curDir = fsConf->listVar.ListCurDir;
    QString path;
    path = fsConf->listVar.SaveResultPath;
    showBottomInfo(QString("flush dir %0").arg(path));
    QDir dir(path);
    if(!dir.exists()){
        dir.mkpath(path);
    }
    // 读取目录
    QFileInfoList dirList;
    QFileInfo info;
    QStringList dirs;
    dirList = dir.entryInfoList(QDir::NoDot|QDir::NoDotAndDotDot|QDir::Dirs,QDir::Name|QDir::Reversed);
    dirs.clear();
    int curIndex=-1;
    if(dirList.count()>0){
        ui->comboBoxResultDir->setEnabled(false);
        curIndex = 0;
        foreach(info,dirList){
            // retInfo(QString("dirList %0 %1 %2 %3").arg(info.baseName()).arg(curDir).arg(curIndex).arg(info.absoluteFilePath()));
            if(!curDir.isEmpty() && curDir.compare(info.baseName(),Qt::CaseInsensitive) == 0){
                //是否为缺省目录
                curIndex = curResultDirList.count();
            }
            curResultDirList.append(info.absoluteFilePath());
            dirs.append(info.fileName());
        }
        // ui->comboBoxResultDir->blockSignals(true);
        ui->comboBoxResultDir->addItems(dirs);
        // ui->comboBoxResultDir->blockSignals(false);
    }
    retInfo(QString("read dir %0 %1").arg(dirs.count()).arg(curIndex));
    curResultDirIndex = curIndex;
    ui->comboBoxResultDir->setEnabled(true);
    if(curResultDirIndex<0){
        //自动新建目录
        on_pushButtonDirNew_clicked();
    }else{
        ui->comboBoxResultDir->setCurrentIndex(curResultDirIndex);
    }
}

//目录新建
void MainWindow::on_pushButtonDirNew_clicked()
{
    QString name = getDirName(fsConf->listVar.SaveDirFormat);
    QString path = QString("%0/%1").arg(fsConf->listVar.SaveResultPath).arg(name);
    // if(isAddDir()){
    //     //修改目录
    //     dirEdit(path);
    //     return;
    // }
    QDir dir(path);
    if(!dir.exists()){
        dir.mkdir(path);
        retInfo(QString("new dir %0 %1").arg(dir.absolutePath()).arg(dir.dirName()));
        qStrToCstr(dir.dirName(),fsConf->listVar.ListCurDir,sizeof(fsConf->listVar.ListCurDir));
        //刷新
        on_pushButtonDirFlush_clicked();
        flushProc();
    }
}

//目录更名
void MainWindow::on_pushButtonDirRen_clicked()
{

}

//目录删除
void MainWindow::on_pushButtonDirDel_clicked()
{
    if(curResultDirList.count()==0)return;
    QDir dir(curResultDirList[curResultDirIndex]);
    retInfo(QString("dir del %0 %1").arg(curResultDirList[curResultDirIndex]).arg(curResultDirIndex));
    if(dir.exists()){
        if(QMessageBox::question(this,
                                  "目录删除",
                                  "删除目录及全部文件，请确认?",
                                  QMessageBox::Yes,
                                  QMessageBox::No) == QMessageBox::Yes){
            //删除目录及目录下文件
            dir.removeRecursively();
            //删除全部ITEM
            delResultFileListItem(-1);
            //刷新
            on_pushButtonDirFlush_clicked();
            flushProc();
        }
    }
}

//目录文件清空
void MainWindow::clearResultFile(void){
    //删除目录下文件
    retInfo("clearResultFile");
    foreach (QString file, curResultFileList)
    {
        retInfo(file);
        QFile::remove(file);
    }
    //删除全部ITEM
    delResultFileListItem(-1);
    //刷新
    ui->listWidgetResultFile->clear();
    curResultFileList.clear();
    ui->labelResultInfo->setText("");
    flushProc();
}

void MainWindow::on_pushButtonDirClear_clicked()
{
    if(curResultFileList.count()==0)return;
    retInfo(QString("dir clear %0").arg(curResultFileList.count()));
    if(QMessageBox::question(this,
                              "目录清空",
                              "删除目录全部文件，请确认?",
                              QMessageBox::Yes,
                              QMessageBox::No) == QMessageBox::Yes){
        clearResultFile();
    }
}

void MainWindow::showResult(void){
    if(curResultFileList.count()&&curResultFileIndex>=0){
        ui->spinBoxResultImageNum->setValue(curResultFileIndex);
        retInfo(QString("showResult %0").arg(curResultFileList[curResultFileIndex]));
        curResultImage = cvRead(curResultFileList[curResultFileIndex], cv::IMREAD_UNCHANGED);
        isResultImage = true;
    }
    flushResult();
}

void MainWindow::flushResult(void){
    if(!isResultImage){
        // ui->labelResultInfo->setText("");
        // ui->labelResultZoomInfo->setText("");
        // ui->labelResultImage->setPixmap(QPixmap());
        return;
    }

    cv::Mat src,image;
    float scale=1.0;

    if(curResultImage.cols<curResultImage.rows){
        cv::rotate(curResultImage.clone(),src,cv::ROTATE_90_COUNTERCLOCKWISE);
    }else{
        src = curResultImage.clone();
    }

    if(curResultImageZoom>0){
        //放大
        float zoom = float(10+curResultImageZoom)/10.0;
        cv::Mat zoomImage = matResize1(src, winResultWidth*zoom, winResultHeight*zoom);
        //位置
        int posX=curResultImagePosX,posY=curResultImagePosY;
        cv::Rect box;
        if((posX+winResultWidth)>=zoomImage.cols){
            posX = zoomImage.cols - winResultWidth;
        }
        if((posY+winResultHeight)>=zoomImage.rows){
            posY = zoomImage.rows - winResultHeight;
        }
        box.x = posX;
        box.y = posY;
        box.width = winResultWidth;
        box.height = winResultHeight;
        image = zoomImage(box);
        retInfo(QString("flush result %0 %1 box %2 %3 %4 %5")
                    .arg(zoomImage.cols).arg(zoomImage.rows)
                    .arg(box.x).arg(box.y).arg(box.width).arg(box.height));
    }else{
        image = matResize(src, winResultWidth, winResultHeight,scale);
    }
    ui->labelResultImage->setPixmap(cvMatToQPixmap(image));
    //轮廓
    isProc= false;
    showContour(src,image,scale);
    flushProc();
}

void MainWindow::flushResultInfo(void){
    ui->labelResultImageInfo->setText(QString("%0-%1 %2-%3")
                                         .arg(curProcShowImage.cols).arg(curProcShowImage.rows)
                                         .arg(curProcSrcImage.cols).arg(curProcSrcImage.rows));
}

//轮廓显示
void MainWindow::showContour(const cv::Mat src,const cv::Mat image,const float scale){
    if(curResultImageZoom>0){
        //不能放大
        return;
    }
    if(!isProc){
        curProcSrcImage = src;
        curProcShowImage = image;
        curProcScale = scale;
    }
    flushResultInfo();
    if(!ui->checkBoxContourRecognition->isChecked()){
        return;
    }
    curProcBox.clear();
    //轮廓识别
    qint64 ms1 = QDateTime::currentMSecsSinceEpoch();
    int result = 0;
    QVector<cv::Rect>boxs;
    result = procContour(image,scale,boxs);
    //轮廓结果
    qint64 ms2 = QDateTime::currentMSecsSinceEpoch();
    retInfo(QString("procContour result %0 %1 nums %2").arg(result).arg(ms2-ms1).arg(boxs.count()));
    for(int pos=0; pos<boxs.count(); pos++){
        // retInfo(QString("%0 box %1 %2 %3 %4").arg(pos).arg(boxs[pos].x).arg(boxs[pos].y).arg(boxs[pos].width).arg(boxs[pos].height));
        // cv::drawContours(image,contours,t,cv::Scalar(0,0,0),1,8);
        cv::rectangle(image,boxs[pos],cv::Scalar(255,255,255),2,8);
        curProcBox.append(boxs[pos]);
    }
    isProc = true;
    //排序-X
    flushProcInfo();
    ui->labelResultImage->setPixmap(cvMatToQPixmap(image));
}

void MainWindow::flushProcInfo(void){
    if(isProc&&curProcBox.count()){
        cv::Rect box = curProcBox.at(0);
        ui->labelProcImageInfo->setText(QString("%0-%1 %2-%3")
                                            .arg(int(box.x*curProcScale)).arg(int(box.y*curProcScale))
                                            .arg(int(box.width*curProcScale)).arg(int(box.height*curProcScale)));
    }else{
        ui->labelProcImageInfo->setText("无识别轮廓");
    }
}

//识别轮廓
int MainWindow::procContour(const cv::Mat image,const float scale,QVector<cv::Rect> &boxs){
    retInfo(QString("procContour %0-%1 %2").arg(image.cols).arg(image.rows).arg(getNumber(scale)));
    cv::Mat binary,image0;
    image0 = image.clone();
    if(fsConf->procVar.ContourGaussian > 0){
        cv::GaussianBlur(image0,image0,
                         cv::Size(fsConf->procVar.ContourGaussian,fsConf->procVar.ContourGaussian),
                         fsConf->procVar.ContourGaussian,fsConf->procVar.ContourGaussian);
    }
    if(image.type() == CV_8UC3){
        cv::cvtColor(image0,image0,cv::COLOR_BGR2GRAY);
    }
    //二值化
    double thresh,t;
    thresh = fsConf->procVar.ContourThresh;
    t = threshold(image0,binary,thresh,255,cv::THRESH_BINARY);
    //图像轮廓计算：面积-基于格林公式，周长-基于L2距离；最大/最小外接轮廓；
    vector<vector<cv::Point>>contours;
    vector<cv::Vec4i>hierarchy;
    //[next-下一个,prev-上一个,first-第一个,parent-父级]
    findContours(binary,contours,hierarchy,cv::RETR_TREE,cv::CHAIN_APPROX_SIMPLE,cv::Point());
    retInfo(QString("conTour %0 , hierarchy %1 ").arg(contours.size()).arg(hierarchy.size()));

    //识别轮廓:1-识别矩形，最大矩形轮廓分割2个矩形，并去除顶部矩形,去除四边；2-去除包含的矩形，并按左至右排序；3-显示矩形边框
    cv::Rect box;
    int minWidth,minHeight,maxWidth;
    minWidth = (float)fsConf->procVar.ContourMinWidth/scale;
    minHeight = (float)fsConf->procVar.ContourMinHeight/scale;
    maxWidth = (float)fsConf->procVar.ContourMaxWidth/scale;
    boxs.clear();
    retInfo(QString("getImageContours %0 %1 %2 %3").arg(contours.size()).arg(minWidth).arg(minHeight).arg(maxWidth));
    for(size_t t=0;t<contours.size();t++){
        // if(hierarchy[t][3] > 0){
        //     //判断非一级
        //     continue;
        // }
        box = boundingRect(contours[t]);
        //比较最小，最大
        if(box.width < minWidth || box.width > maxWidth || box.height < minHeight){
            continue;
        }
        // retInfo(QString("%0 Contours box %1 %2 %3 %4").arg(t).arg(box.x).arg(box.y).arg(box.width).arg(box.height));
        if(isInBox(box, boxs)){
            continue;
        }
        // cv::drawContours(image,contours,t,cv::Scalar(0,0,0),1,8);
        // cv::rectangle(image,box,cv::Scalar(255,255,255),2,8);
        boxs.append(box);
    }
    //排序
    sortBox(boxs,boxs);
/*
    curImageOverType = blackImageBorderBox(image0,maxBox,
                                           QSize(winImageWidth,winImageHeight),
                                           QSize(fsConf->scanVar.ScanContourXWhite,fsConf->scanVar.ScanContourYWhite));
*/
    //    if(maxBox.x == 0 || maxBox.y == 0 || (maxBox.x+maxBox.width) == winImageWidth || (maxBox.y+maxBox.height) == winImageHeight){
    //判断超界类型
    //增加白边
    //        for(int i=0;i<fsConf->scanVar.ScanContourYWhite;i++){
    //            if(maxBox.y == 0){
    //                line(image0,Point(0,maxBox.y+i),Point(maxBox.width-1,maxBox.y+i),Scalar(0,0,0),1,8,0);
    //            }
    //            if((maxBox.y+maxBox.height) == winImageHeight){
    //                line(image0,Point(0,maxBox.y+maxBox.height-fsConf->scanVar.ScanContourYWhite+i),
    //                     Point(maxBox.width-1,maxBox.y+maxBox.height-fsConf->scanVar.ScanContourYWhite+i),Scalar(0,0,0),1,8,0);
    //            }
    //        }
    //        for(int i=0;i<fsConf->scanVar.ScanContourXWhite;i++){
    //            if(maxBox.x == 0){
    //                line(image0,Point(maxBox.x+i,maxBox.y),Point(maxBox.x+i,maxBox.y+maxBox.height-1),Scalar(0,0,0),1,8,0);
    //            }
    //            if((maxBox.x+maxBox.width) == winImageWidth){
    //                line(image0,Point(maxBox.x+maxBox.width-fsConf->scanVar.ScanContourXWhite+i,maxBox.y),
    //                     Point(maxBox.x+maxBox.width-fsConf->scanVar.ScanContourXWhite+i,maxBox.y+maxBox.height-1),Scalar(0,0,0),1,8,0);
    //            }
    //        }
    //    }
/*
 *     if(curImageOverType>0){
        if(!bPreviewMode)return 0;
        //重新识别轮廓
        contours.clear();
        threshold(image0,binary,0,255,cv::THRESH_BINARY|cv::THRESH_OTSU);
        findContours(binary,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());
        if(fsConf->funcVar.Debug){
            retInfo(QString("reconTour size %0").arg(contours.size()));
        }
    }
*/
    //找最大轮廓
/*
    vector<Point> contoursMax;
    vector<Point> contoursHull;
    int areaMax=-1,pos=-1;
    pos = getImageContoursMax(contours,hierarchy,maxBox,areaMax,fsConf->scanVar.ScanContourMinWidth,fsConf->scanVar.ScanContourMinHeight);
*/
    //    for(size_t t=0;t<contours.size();t++){
    //        int p1 = hierarchy[t][3];
    //        int p2 = hierarchy[p1][3];
    //        //第一父级过滤
    //        if(p1 > 0){
    //            continue;
    //        }
    //        //保留第一级
    //        int area = int(contourArea(contours[t]));
    //        if(areaMax<0 || area > areaMax){
    //            maxBox = boundingRect(contours[t]);
    //            if(maxBox.width < fsConf->scanVar.ScanContourMinWidth || maxBox.height < fsConf->scanVar.ScanContourMinHeight){
    //                //最小轮廓限制
    //                continue;
    //            }
    //            areaMax = area;
    //            pos = t;
    //        }
    //    }
/*
    if(pos < 0){
        //无有效轮廓
        return 0;
    }

    //最大轮廓
    contoursMax = contours[pos];
    //polylines(image0, contoursMax, true, Scalar(0,0,255),1,8,0);
    //最大轮廓矩形
    maxBox = boundingRect(contoursMax);
    //cutWin->recvImageBox(maxBox.x - winImageOffX ,maxBox.y - winImageOffY, maxBox.width, maxBox.height);
    //rectangle(image0,maxBox,Scalar(0,255,0),2,8);
    //凸包
    if(curImageOverType == 0){
        convexHull(contoursMax,contoursHull,true,true);
        maxBox = boundingRect(contoursHull);
    }
    //右上角坐标
    //for(int i=0;i<contoursMax.size();i++){
    //    circle(image0,contoursMax[i],2,Scalar(255,0,0),1,8);
    //}
    //找最大内矩形
    minBox = maxBox;
    //    retInfo(QString("minBox %0 %1 %2 %3").arg(minBox.x).arg(minBox.y).arg(minBox.width).arg(minBox.height));
    if(curImageOverType>0 && maxInnerRect(contoursMax, minBox)){
        //        qint64 ms = QDateTime::currentMSecsSinceEpoch();
        //        retInfo(QString("minBox %0 %1 %2 %3").arg(minBox.x).arg(minBox.y).arg(minBox.width).arg(minBox.height));
        if(curImageOverType==1){
            //左上角-右下角对齐
            int w = (maxBox.x + maxBox.width) - (minBox.x + minBox.width);
            int h = (maxBox.y + maxBox.height) - (minBox.y + minBox.height);
            if(w>0)minBox.width += w;
            if(h>0)minBox.height += h;
            //二次轮廓：最大轮廓变黑至最小轮廓
            blackImageBox(image0,minBox);
        }
        else{
            //右上角-左下角对齐
            int w = maxBox.x - minBox.x;
            int h = (maxBox.y + maxBox.height) - (minBox.y + minBox.height);
            if(w<0){
                minBox.x = maxBox.x;
                minBox.width -= w;
            }
            if(h>0)minBox.height += h;
            //二次轮廓：最大轮廓变黑至最小轮廓
            blackImageBox(image0,minBox);
        }
        //rectangle(image0,minBox,Scalar(0,255,255),2,8);
        //        ms = QDateTime::currentMSecsSinceEpoch() - ms;
        //        retInfo(QString("time ms %0 ").arg(ms));
        //二次最大轮廓，最大内矩形
        contours.clear();
        threshold(image0,binary,0,255,cv::THRESH_BINARY|cv::THRESH_OTSU);
        findContours(binary,contours,hierarchy,RETR_TREE,CHAIN_APPROX_SIMPLE,Point());
        //    retInfo(QString("reconTour2 size %0").arg(contours.size()));
        pos = getImageContoursMax(contours,hierarchy,maxBox,areaMax,fsConf->scanVar.ScanContourMinWidth,fsConf->scanVar.ScanContourMinHeight);
        if(pos<0){
            return 0;
        }
        //最大轮廓
        contoursMax = contours[pos];
        //最大轮廓矩形
        maxBox = boundingRect(contoursMax);
        //找最大内矩形
        minBox = maxBox;
    }
    cutWin->recvImageBox(maxBox.x - winImageOffX ,maxBox.y - winImageOffY, maxBox.width+1, maxBox.height+1);
    if(curImageOverType>0 && maxInnerRect(contoursMax, minBox)){
        //最大内矩形
        cutWin->recvImageBox(minBox.x - winImageOffX ,minBox.y - winImageOffY, minBox.width+1, minBox.height+1,QColor(255,255,0),2);
        if(fsConf->funcVar.Debug){
            retInfo(QString("minBox %0 %1 %2 %3").arg(minBox.x).arg(minBox.y).arg(minBox.width).arg(minBox.height));
        }
    }
*/
    return 0;
}

//列表文件
void MainWindow::on_listWidgetResultFile_currentRowChanged(int currentRow)
{
    retInfo(QString("on_listWidgetResultFile_currentRowChanged %0").arg(currentRow));
    curResultFileIndex = currentRow;
    if(currentRow<0){
        return;
    }
    ui->listWidgetResultFile->scrollToItem(ui->listWidgetResultFile->item(currentRow));
    ui->listWidgetResultFile->item(currentRow)->setSelected(true);

    // curImageFilename = curImageFileList[curImageFileIndex];
    //读取文件
    ui->spinBoxResultImageNum->setValue(curResultFileIndex);
    QImage img;
    img.load(curResultFileList[curResultFileIndex]);
    QFileInfo info(curResultFileList[curResultFileIndex]);
    qStrToCstr(info.fileName(),fsConf->listVar.ListCurName,sizeof(fsConf->listVar.ListCurName));
    getFilename(info.baseName(),curResultFileNo);
    retInfo(QString("current FileList name %0 %1 %2").arg(curResultFileList[curResultFileIndex]).arg(curResultFileNo[0]).arg(curResultFileNo[1]));
    // QString mean = getNumber(nameLightMean(curImageFilename), 2);
    // QString clearness = getNumber(nameImageClearness(curImageFilename), 2);
    // showTopImageInfo(QString("图片[%0]信息[%1x%2 %3 %4]")
    //                      .arg(curImageFilename).arg(img.width()).arg(img.height()).arg(mean).arg(clearness));
    showResult();
}

//拍照
void MainWindow::on_pushButtonPhotograph_clicked()
{
    if(bAutoPhoto){
        return;
    }

}

//无轮廓双边
void MainWindow::on_checkBoxNonContourTwoBorder_toggled(bool checked)
{
    if((int)checked == fsConf->procVar.ContourTwoBorder){
        return;
    }
    fsConf->procVar.ContourTwoBorder = checked;
    fsConf->saveConfigProc();
    flushResult();
}

//阈值
void MainWindow::on_spinBoxContourThreshold_valueChanged(int arg1)
{
    if(arg1 == fsConf->procVar.ContourThresh){
        return;
    }
    fsConf->procVar.ContourThresh = arg1;
    fsConf->saveConfigProc();
    flushResult();
}

//高斯
void MainWindow::on_spinBoxContourGaussian_valueChanged(int arg1)
{
    if(arg1 == fsConf->procVar.ContourGaussian){
        return;
    }
    fsConf->procVar.ContourGaussian = arg1;
    fsConf->saveConfigProc();
    flushResult();
}

//最小轮廓
void MainWindow::on_spinBoxContourMinWidth_valueChanged(int arg1)
{
    if(arg1 == fsConf->procVar.ContourMinWidth){
        return;
    }
    fsConf->procVar.ContourMinWidth = arg1;
    fsConf->saveConfigProc();
    flushResult();
}

void MainWindow::on_spinBoxContourMinHeight_valueChanged(int arg1)
{
    if(arg1 == fsConf->procVar.ContourMinHeight){
        return;
    }
    fsConf->procVar.ContourMinHeight = arg1;
    fsConf->saveConfigProc();
    flushResult();
}

//上下边界
void MainWindow::on_spinBoxUpDownBorder_valueChanged(int arg1)
{
    if(arg1 == fsConf->procVar.ContourUpDownBorder){
        return;
    }
    fsConf->procVar.ContourUpDownBorder = arg1;
    fsConf->saveConfigProc();
    flushResult();
}

//左右边界
void MainWindow::on_spinBoxLeftRightBorder_valueChanged(int arg1)
{
    if(arg1 == fsConf->procVar.ContourLeftRightBorder){
        return;
    }
    fsConf->procVar.ContourLeftRightBorder = arg1;
    fsConf->saveConfigProc();
    flushResult();
}

//图片最大宽度
void MainWindow::on_spinBoxImageMaxWidth_valueChanged(int arg1)
{
    if(arg1 == fsConf->procVar.ProcImageWidth){
        return;
    }
    fsConf->procVar.ProcImageWidth = arg1;
    fsConf->saveConfigProc();
    flushResult();
}

//清空处理目录文件
void MainWindow::clearProcFile(void){
    QFileInfoList fileList;
    QFileInfo info;
    QDir dir(getCurProcDir());
    fileList = dir.entryInfoList(QDir::NoDot|QDir::NoDotAndDotDot|QDir::Files,QDir::Name);
    retInfo(QString("clearProcFile %0 %1").arg(dir.absolutePath()).arg(fileList.count()));
    if(fileList.count()>0){
        foreach(info,fileList){
            QFile::remove(info.absoluteFilePath());
        }
    }
}

QString MainWindow::getCurProcDir(void){
    return QString("%0/%1").arg(fsConf->listVar.SaveImagePath).arg(ui->comboBoxResultDir->currentText());
}

//开启轮廓
void MainWindow::on_checkBoxContourRecognition_toggled(bool checked)
{
    Q_UNUSED(checked);
    //重新显示
    flushResult();
}

//定时处理
void MainWindow::updateProcTimer(void){
    retInfo(QString("updateProcTimer %0").arg(isProc));
    if(isProc){
        if(curProcBox.count()>1 || curProcSrcImage.cols > (ui->spinBoxImageMaxWidth->value()*2)){
            on_pushButtonContourCut_clicked();
        }else{
            on_pushButtonContourAdd_clicked();
        }
    }
}

//自动处理
void MainWindow::on_pushButtonAutoContour_clicked()
{
    bAutoProc = !bAutoProc;
    retInfo(QString("AutoContour %0 %1").arg(bAutoProc).arg(fsConf->procVar.ProcTime));

    if(bAutoProc){
        emit ui->listWidgetResultFile->setCurrentRow(0);
        clearProcFile();
        ui->spinBoxProcImageNum->setValue(1);
        procTimer->start(fsConf->procVar.ProcTime);
    }else{
        procTimer->stop();
    }
    flushPushButton(ui->pushButtonAutoContour,bAutoProc);
    flushProc();
}

//续接
void MainWindow::on_pushButtonContourAdd_clicked()
{
    if(!isProc){
        return;
    }
    int index = ui->spinBoxResultImageNum->value() + 1;
    if(index >= curResultFileList.count()){
        //最后一个
        return;
    }
    saveImageMutex->lock();

    ui->spinBoxResultImageNum->setValue(index);
    retInfo(QString("ContourAdd %0").arg(index));
    cv::Mat img = cvRead(curResultFileList[index], cv::IMREAD_UNCHANGED);
    //续接
    cv::hconcat(curProcSrcImage,img,curProcSrcImage);
    //续接显示
    curProcShowImage = matResize(curProcSrcImage, winResultWidth, winResultHeight,curProcScale);
    ui->labelResultImage->setPixmap(cvMatToQPixmap(curProcShowImage));
    showContour(curProcSrcImage,curProcShowImage,curProcScale);

    saveImageMutex->unlock();
}

//切图
void MainWindow::on_pushButtonContourCut_clicked()
{
    if(!isProc){
        return;
    }
    saveImageMutex->lock();

    bool noBox = true;
    cv::Rect box = {0,0,curProcShowImage.cols,curProcShowImage.rows};
    if(curProcBox.count()){
        noBox = false;
        box = curProcBox.takeFirst();
    }
    //切图轮廓
    cv::Rect cutBox = boxScale(box,curProcScale);
    //增加边界
    int bh = ui->spinBoxUpDownBorder->value();
    int bw = ui->spinBoxLeftRightBorder->value();
    while(true){
        //判断左边界大于最小轮廓或大于最大宽度切无轮廓图
        if(cutBox.x > ui->spinBoxContourMinWidth->value()){
            //切无轮廓图
            cutBox.width = cutBox.x;
            cutBox.x = 0;
            cutBox.y = 0;
            cutBox.height = curProcSrcImage.rows;
            break;
        }
        //判断宽度大于最大宽度切无轮廓图
        if(noBox&&cutBox.width > ui->spinBoxImageMaxWidth->value()){
            //切无轮廓图
            cutBox.x = 0;
            cutBox.y = 0;
            cutBox.width = ui->spinBoxImageMaxWidth->value();
            cutBox.height = curProcSrcImage.rows;
            break;
        }
        //轮廓图
        if(cutBox.y<bh){
            cutBox.height += cutBox.y;
            cutBox.y = 0;
        }else{
            cutBox.y -= bh;
            cutBox.height += bh;
        }
        if((curProcSrcImage.rows - cutBox.y - cutBox.height)<bh){
            cutBox.height += curProcSrcImage.rows - cutBox.y - cutBox.height;
        }else{
            cutBox.height += bh;
        }

        if(cutBox.x<bw){
            cutBox.width += cutBox.x;
            cutBox.x = 0;
        }else{
            cutBox.x -= bw;
            cutBox.width += bw;
        }
        if((curProcSrcImage.cols - cutBox.x - cutBox.width)<bw){
            cutBox.width += curProcSrcImage.cols - cutBox.x - cutBox.width;
        }else{
            cutBox.width += bw;
        }
        break;
    }

    cv::Mat img = curProcSrcImage(cutBox);

    retInfo(QString("ContourCut %0 box %1 %2 %3 %4").arg(curProcBox.count()).arg(cutBox.x).arg(cutBox.y).arg(cutBox.width).arg(cutBox.height));

    QString name="",ext="";
    ext = QString(fsConf->designVar.SaveFileExt).split(",").at(fsConf->designVar.SaveFormat);
    setFilename(ui->spinBoxProcImageNum->value(),name,getCurProcDir(),ext,fsConf->listVar.SaveFileLen);

    retInfo(QString("save proc %0 %1 %2").arg(img.cols).arg(img.rows).arg(name));

    cvMatImageSave(img, name, false, fsConf->designVar.SaveFormat, fsConf->designVar.Para);
    saveImageEx(name, fsConf->designVar.SaveDPI);
    ui->spinBoxProcImageNum->setValue(ui->spinBoxProcImageNum->value()+1);

    //切图显示
    cutBox.x += cutBox.width;
    cutBox.y = 0;
    cutBox.width = curProcSrcImage.cols - cutBox.x;
    cutBox.height = curProcSrcImage.rows;

    curProcSrcImage = curProcSrcImage(cutBox);

    curProcShowImage = matResize(curProcSrcImage, winResultWidth, winResultHeight,curProcScale);
    ui->labelResultImage->setPixmap(cvMatToQPixmap(curProcShowImage));
    showContour(curProcSrcImage,curProcShowImage,curProcScale);

    saveImageMutex->unlock();
}

